« get me outta code hell

Move keybinder code into its own file - http-music - Command-line music player + utils (not a server!)
about summary refs log tree commit diff
diff options
context:
space:
mode:
authorFlorrie <towerofnix@gmail.com>2017-09-03 13:35:08 -0300
committerFlorrie <towerofnix@gmail.com>2017-09-03 13:35:08 -0300
commit7b4916c4c59c95a8c0e4fb558f4305cd63a3b578 (patch)
tree3bf9e0ee96cc16d48120fd10a5cde200bbcd612c
parent0657579988dddac3040fb84a0f8743d8caab95b4 (diff)
Move keybinder code into its own file
-rw-r--r--src/keybinder.js61
-rwxr-xr-xsrc/play.js48
2 files changed, 66 insertions, 43 deletions
diff --git a/src/keybinder.js b/src/keybinder.js
new file mode 100644
index 0000000..1d80348
--- /dev/null
+++ b/src/keybinder.js
@@ -0,0 +1,61 @@
+const splitChars = str => str.split('').map(char => char.charCodeAt(0))
+
+const simpleKeybindings = {
+  space: [0x20],
+  esc: [0x1b], escape: [0x1b],
+  up: [0x1b, ...splitChars('[A')],
+  down: [0x1b, ...splitChars('[B')],
+  right: [0x1b, ...splitChars('[C')],
+  left: [0x1b, ...splitChars('[D')],
+  shiftUp: [0x1b, ...splitChars('[1;2A')],
+  shiftDown: [0x1b, ...splitChars('[1;2B')],
+  shiftRight: [0x1b, ...splitChars('[1;2C')],
+  shiftLeft: [0x1b, ...splitChars('[1;2D')],
+  delete: [0x7f]
+}
+
+module.exports.compileKeybindings = function(bindings, commands) {
+  const handlers = bindings.map(binding => {
+    const [ keys, command, ...args] = binding
+
+    if (!commands.hasOwnProperty(command)) {
+      console.warn('Invalid command', command, 'in keybinding', binding)
+      return
+    }
+
+    let failed = false
+
+    const bufferParts = keys.map(item => {
+      if (typeof item === 'number') {
+        return [item]
+      } else if (Object.keys(simpleKeybindings).includes(item)) {
+        return simpleKeybindings[item]
+      } else if (typeof item === 'string' && item.length === 1) {
+        return [item.charCodeAt(0)]
+      } else {
+        // Error
+        console.warn('Invalid keybinding part', item, 'in keybinding', bindings)
+        failed = true
+        return []
+      }
+    }).reduce((a, b) => a.concat(b), [])
+
+    if (failed) {
+      return
+    }
+
+    const buffer = Buffer.from(bufferParts)
+
+    return function(inputData) {
+      if (buffer.equals(inputData)) {
+        commands[command](...args)
+      }
+    }
+  }).filter(Boolean)
+
+  return function(inputData) {
+    for (let handler of handlers) {
+      handler(inputData)
+    }
+  }
+}
diff --git a/src/play.js b/src/play.js
index 558a561..bf39565 100755
--- a/src/play.js
+++ b/src/play.js
@@ -9,6 +9,7 @@ const fetch = require('node-fetch')
 const commandExists = require('./command-exists')
 const startLoopPlay = require('./loop-play')
 const processArgv = require('./process-argv')
+const { compileKeybindings } = require('./keybinder')
 const processSmartPlaylist = require('./smart-playlist')
 
 const {
@@ -366,7 +367,7 @@ async function main(args) {
       'doNothing': function() {},
 
       // TODO: Separate pause and unpause commands
-      'toggle_pause': function() {
+      'togglePause': function() {
         player.togglePause()
       },
 
@@ -437,25 +438,9 @@ async function main(args) {
       }
     }
 
-    const splitChars = str => str.split('').map(char => char.charCodeAt(0))
-
-    const simpleKeybindings = {
-      space: [0x20],
-      esc: [0x1b], escape: [0x1b],
-      up: [0x1b, ...splitChars('[A')],
-      down: [0x1b, ...splitChars('[B')],
-      right: [0x1b, ...splitChars('[C')],
-      left: [0x1b, ...splitChars('[D')],
-      shiftUp: [0x1b, ...splitChars('[1;2A')],
-      shiftDown: [0x1b, ...splitChars('[1;2B')],
-      shiftRight: [0x1b, ...splitChars('[1;2C')],
-      shiftLeft: [0x1b, ...splitChars('[1;2D')],
-      delete: [0x7f]
-    }
-
     // TODO: Load these from a file
     // TODO: Verify that each command exists
-    const commandBindings = {
+    const keybindingHandler = compileKeybindings({
       bindings: [
         [['space'], 'togglePause'],
         [['left'], 'seek', -5],
@@ -470,7 +455,7 @@ async function main(args) {
         [['t'], 'showTrackInfo'],
         [['q'], 'quit']
       ]
-    }
+    }.bindings, commands)
 
     process.stdin.on('data', data => {
       const escModifier = Buffer.from('\x1b[')
@@ -498,30 +483,7 @@ async function main(args) {
         return
       }
 
-      for (let [ keyBinding, command, ...args ] of commandBindings.bindings) {
-        let run = true
-
-        // TODO: "Compile" keybindings upon loading them
-        const buffer = Buffer.from(keyBinding.map(item => {
-          if (typeof item === 'number') {
-            return [item]
-          } else if (Object.keys(simpleKeybindings).includes(item)) {
-            return simpleKeybindings[item]
-          } else if (typeof item === 'string' && item.length === 1) {
-            return [item.charCodeAt(0)]
-          } else {
-            // Error
-            console.warn('Invalid keybinding part?', item, 'in', keyBinding)
-            return [0xFF]
-          }
-        }).reduce((a, b) => a.concat(b), []))
-
-        run = buffer.equals(data)
-
-        if (run && Object.keys(commands).includes(command)) {
-          commands[command](...args)
-        }
-      }
+      keybindingHandler(data)
     })
 
     return playPromise