147 lines
5.0 KiB
JavaScript
Executable File
147 lines
5.0 KiB
JavaScript
Executable File
#!/bin/env node
|
|
|
|
// ---
|
|
const TYPE_CHARS = /^[@!:=\s]/
|
|
const KEY_SYMS = require("./keys.js")
|
|
const KEY_SYMS_KEYS = KEY_SYMS.keys.map(keySym => keySym.toUpperCase())
|
|
const KEY_SYMS_MODS = KEY_SYMS.modifiers.map(keySym => keySym.toUpperCase())
|
|
// ---
|
|
|
|
const fs = require("fs")
|
|
const { exec } = require("child_process")
|
|
|
|
if (!process.argv[2]) {
|
|
console.error("You need to provide a path to the config!")
|
|
exit(1)
|
|
}
|
|
|
|
if (!fs.existsSync(process.argv[2])) {
|
|
console.error("That file doesn't exist!")
|
|
process.exit(2)
|
|
}
|
|
|
|
const CONFIG = fs.readFileSync(process.argv[2]).toString()
|
|
|
|
// Remove irrelevant lines. (Empty and comments)
|
|
const LINES = CONFIG.split('\n').filter(LINE => LINE && !LINE.match(/^#[\S\s]*$/))
|
|
|
|
// Tokenize the lines into KBD (keyboard shortcuts), CMD (commands), and DEF (variable definitions)
|
|
const TOKENS = LINES.map(
|
|
LINE => {
|
|
const TYPES = LINE.match(TYPE_CHARS)
|
|
|
|
if (!TYPES)
|
|
return {
|
|
type: "KBD",
|
|
repeat: false,
|
|
release: false,
|
|
mode: "normal",
|
|
binding: LINE.replace(TYPE_CHARS, ''),
|
|
}
|
|
|
|
if (TYPES[0].match(/^\s/))
|
|
return {
|
|
type: "CMD",
|
|
command: LINE.replace(/^\s*/, '')
|
|
}
|
|
|
|
if (TYPES[0].match(/^=/))
|
|
return {
|
|
type: "DEF",
|
|
key: LINE.replace(/=\s*/, '').split(/\s+/)[0],
|
|
value: LINE.replace(/=\s*/, '').split(/\s+/).slice(1).join(' ')
|
|
}
|
|
|
|
const IS_REPEATING = TYPES[0].match(/!/) ? true : false
|
|
const IS_ON_RELEASE = TYPES[0].match(/@/) ? true : false
|
|
const IS_IN_DIFFERENT_MODE = TYPES[0].match(/:/) ? true : false
|
|
|
|
return {
|
|
type: "KBD",
|
|
repeat: IS_REPEATING,
|
|
release: IS_ON_RELEASE && IS_REPEATING ? false : IS_ON_RELEASE,
|
|
mode: IS_IN_DIFFERENT_MODE
|
|
? LINE.replace(TYPE_CHARS, '').match(/^\S+/)[0]
|
|
: "normal",
|
|
binding: IS_IN_DIFFERENT_MODE
|
|
? LINE.replace(TYPE_CHARS, '').replace(/^\S+\s+/, '')
|
|
: LINE.replace(TYPE_CHARS, '')
|
|
}
|
|
}
|
|
)
|
|
|
|
const parseVariables = (input, defMap) =>
|
|
input.replace(
|
|
/\$\w+/,
|
|
match => {
|
|
const VAR_NAME = match.replace("$", "")
|
|
if (defMap[VAR_NAME])
|
|
return defMap[VAR_NAME]
|
|
|
|
console.error("\nUsed undefined or empty variable:", VAR_NAME,
|
|
"\nContext:", input,
|
|
"\nVariables in scope:", defMap,
|
|
)
|
|
}
|
|
)
|
|
|
|
let defMap = {}
|
|
let cursor = 0
|
|
while (cursor < TOKENS.length) {
|
|
const TOKEN = TOKENS[cursor]
|
|
switch (TOKEN.type) {
|
|
case "DEF":
|
|
defMap[TOKEN.key] = TOKEN.value
|
|
++cursor
|
|
break
|
|
|
|
case "KBD":
|
|
const PARSE_VARS = parseVariables(TOKEN.binding, defMap)
|
|
const ALL_KEYS = PARSE_VARS.split(/\s*\+\s*/)
|
|
const MOD_KEYS = ALL_KEYS.filter(key => KEY_SYMS_MODS.includes(key.toUpperCase()))
|
|
const NORM_KEY = ALL_KEYS.filter(key => KEY_SYMS_KEYS.includes(key.toUpperCase()))
|
|
const WTF_KEYS = ALL_KEYS.filter(key => !KEY_SYMS_KEYS.includes(key.toUpperCase()) && !KEY_SYMS_MODS.includes(key.toUpperCase()))
|
|
|
|
const WTF_KEYS_ERR = WTF_KEYS[0] ? true : false
|
|
const NORM_KEY_ERR = NORM_KEY.length > 1
|
|
const NO_KEY_ERR = !NORM_KEY[0] ? true : false
|
|
const NXT_TKN_ERR = TOKENS[cursor + 1]?.type !== "CMD"
|
|
|
|
if (WTF_KEYS_ERR || NORM_KEY_ERR || NO_KEY_ERR || NXT_TKN_ERR) {
|
|
WTF_KEYS_ERR ? console.error("\nWtf do you mean with these keys?", WTF_KEYS) : null
|
|
NORM_KEY_ERR ? console.error("\nYou have more than one key specified!", NORM_KEY) : null
|
|
NO_KEY_ERR ? console.error("\nYou haven't specified a key!") : null
|
|
NXT_TKN_ERR ? console.error("\nKeybinding is not followed by command!", ALL_KEYS.join(" + ")) : null
|
|
++cursor
|
|
break
|
|
}
|
|
|
|
const MODE = TOKEN.mode
|
|
const REPEAT = TOKEN.repeat ? "-repeat " : ""
|
|
const RELEASE = TOKEN.release ? "-release " : ""
|
|
const MOD = MOD_KEYS[0] ? MOD_KEYS.join("+") : "None"
|
|
const KEY = NORM_KEY[0] ?? ""
|
|
const COMMAND = TOKENS[cursor + 1].command
|
|
|
|
const RUN_CMD = `riverctl map ${REPEAT}${RELEASE}${MODE} ${MOD} ${KEY} ${COMMAND}`
|
|
|
|
console.log("\nRunning command:", RUN_CMD)
|
|
exec(
|
|
RUN_CMD,
|
|
(err, stdout, stderr) => {
|
|
err && console.error("\nError while running command!\n", err)
|
|
stdout && console.log("\nSTDOUT:", stdout)
|
|
stderr && console.log("\nSTDOUT:", stderr)
|
|
}
|
|
)
|
|
|
|
cursor += 2
|
|
break
|
|
|
|
default:
|
|
++cursor
|
|
break
|
|
}
|
|
}
|
|
|