mirror of
https://github.com/ebeem/guile-swayer.git
synced 2024-12-26 21:59:03 +01:00
192 lines
7.7 KiB
Scheme
Executable file
192 lines
7.7 KiB
Scheme
Executable file
(define-module (modules general)
|
|
#:use-module (sjson parser)
|
|
#:use-module (swayipc dispatcher)
|
|
#:use-module (swayipc connection)
|
|
#:use-module (srfi srfi-18)
|
|
#:use-module (ice-9 hash-table)
|
|
#:export (general-keybinding-translator
|
|
general-commander-path
|
|
general-configure
|
|
general-define-keys
|
|
general-define-key
|
|
general-keybindings
|
|
general-submaps))
|
|
|
|
;; Local copy of keybindings configured by general, it's recommended to
|
|
;; only use general to assign keybindings, otherwise this hashtable won't
|
|
;; by synced with actual keybindings available in sway
|
|
(define general-keybindings (make-hash-table))
|
|
|
|
;; Local copy of submaps configured by general, it's recommended to
|
|
;; only use general to assign submaps, otherwise this hashtable won't
|
|
;; by synced with actual submaps available in sway
|
|
(define general-submaps (make-hash-table))
|
|
|
|
;; add default submap, this is the default submap in sway
|
|
(hash-set! general-submaps "" "default")
|
|
|
|
(define (general-keybinding-translator key)
|
|
"Translate a given key, passing a function can enable easier keybindings
|
|
like emacs key chords (refer to module modules/kbd.scm). The default implementation
|
|
doesn't modify passed keybindings"
|
|
key)
|
|
|
|
;; The path of commander executable, it's used to send back scheme expressions
|
|
;; via unix socket.
|
|
(define general-commander-path
|
|
(if current-filename
|
|
(string-append (dirname (dirname current-filename)) "/commander")
|
|
"commander"))
|
|
|
|
(define* (general-configure #:key keybinding-translator commander-path)
|
|
"Configure keybinding-translator (refer to general-keybinding-translator) and
|
|
commander-path (refer to 'general-commander-path).
|
|
Parameters:
|
|
- keybinding-translator: a function that takes a key and returns the translated version.
|
|
- commander-path: a path to the commander executable to be used to send keybindings commands."
|
|
(when keybinding-translator
|
|
(set! general-keybinding-translator keybinding-translator))
|
|
(when commander-path
|
|
(set! general-commander-path commander-path)))
|
|
|
|
(define (exp->string exp)
|
|
"Convert a given expression exp to a string."
|
|
(call-with-output-string (lambda (p)
|
|
(write exp p))))
|
|
|
|
(define* (define-submap chord wk submap parent-submap)
|
|
"Define a submap, this will be translated to sway by defining a keybinding
|
|
to switch to the provided submap, and add a default ESC keybinding to return
|
|
to the default submap.
|
|
Parameters:
|
|
- chord: chord string to trigger the keybinding. e.g. (s-SPC f f).
|
|
- wk: which-key's description.
|
|
- submap: the name of the submap.
|
|
- parent-submap: parent submap, default if submap is a child of the default submap."
|
|
(let* ((chord-ls (map general-keybinding-translator
|
|
(string-split chord #\Space)))
|
|
(key (car (last-pair chord-ls))))
|
|
(format #t "define submap ~a\n" chord)
|
|
(hash-set! general-submaps chord submap)
|
|
(define-keybindings chord
|
|
`(sway-mode ,submap)
|
|
wk parent-submap)
|
|
(define-keybindings (string-append chord " Esc")
|
|
`(sway-mode "default")
|
|
"Escape" submap)))
|
|
|
|
(define (last-key chord)
|
|
"Return last key from a given chord."
|
|
(car (reverse (string-split chord #\+))))
|
|
|
|
(define (general-command exp-str)
|
|
"Execute a general command (scheme expression)"
|
|
(string-append "exec '" general-commander-path " "
|
|
(exp->string exp-str) "'"))
|
|
|
|
(define* (define-keybindings chord exp wk submap)
|
|
"Define a sway keybinding.
|
|
Parameters:
|
|
- chord: chord string to trigger the keybinding. e.g. (s-SPC f f).
|
|
- exp: expression to execute when the chord is triggered.
|
|
- wk: which-key's description.
|
|
- submap: the name of the submap."
|
|
(let* ((chord-ls (map general-keybinding-translator
|
|
(string-split chord #\Space)))
|
|
(key (car (last-pair chord-ls)))
|
|
(type (if (string->number (last-key key)) "bindcode" "bindsym"))
|
|
(command (string-append type " " key " " (general-command (exp->string exp))))
|
|
(esc (string-append type " " key " " (general-command (exp->string `(and ,exp (sway-mode "default")))))))
|
|
|
|
(hash-set! general-keybindings chord '(key exp wk submap))
|
|
(if (equal? submap "default")
|
|
(dispatch-command command)
|
|
(begin
|
|
(sway-mode-subcommand submap command)
|
|
(unless (equal? "sway-mode" (symbol->string (car exp)))
|
|
(sway-mode-subcommand submap esc))))))
|
|
|
|
(define (find-submap chord)
|
|
"Return the submap for the provided chord.
|
|
If the submap isn't found, #f is returned."
|
|
(or
|
|
(hash-get-handle general-submaps
|
|
(string-join
|
|
(list-head chord (- (length chord) 1)) " "))
|
|
#f))
|
|
|
|
(define* (general-define-key chord #:optional exp #:key wk submap)
|
|
"Assign a given chord to a given expression.
|
|
Parameters:
|
|
- chord: chord string to trigger the keybinding. e.g. (s-SPC f f).
|
|
- exp: expression to execute when the chord is triggered.
|
|
- wk: which-key's description.
|
|
- submap: the name of the submap."
|
|
(let* ((chord-ls
|
|
(map general-keybinding-translator
|
|
(string-split chord #\Space)))
|
|
(key (car (last-pair chord-ls)))
|
|
(chord (string-join chord-ls " "))
|
|
(key-code (string->number key))
|
|
(description (or wk (or submap (symbol->string (car exp)))))
|
|
(tsubmap (cdr (find-submap chord-ls))))
|
|
|
|
;; if target submap isn't found, throw an error
|
|
;; the submap must always be defined before defining a keybinding
|
|
(unless tsubmap
|
|
(error 'find-submap "chord was not found in submaps, a submap has to be defined for it" chord))
|
|
|
|
(if submap
|
|
;; if submap key is provided, then define a submap (ignore exp)
|
|
(define-submap chord wk submap
|
|
(cdr (find-submap chord-ls)))
|
|
;; otherwise, define a keybinding with exp
|
|
(define-keybindings chord exp wk
|
|
(cdr (find-submap chord-ls))))))
|
|
|
|
(define* (general-define-keys #:key parent-prefix prefix wk . args )
|
|
"Assign given list of chords and expressions to a submap.
|
|
Parameters:
|
|
- prefix: a prefix that's applied to all the keybindings passed. e.g. (s-Spc).
|
|
- parent-prefix: a prefix of the parent (passed internally, you should probably use prefix instead).
|
|
- wk: which-key's description of the submap.
|
|
- args: list of keybindings to assign to the prefix, these will be passed to general-define-key.
|
|
|
|
For example:
|
|
(general-define-keys
|
|
#:prefix \"s-Space\" #:wk \"Leader\"
|
|
`(\"o\" (exec \"rofi -show drun\"))
|
|
`(\"C-g\" (sway-mode \"default\") #:wk \"abort\")
|
|
|
|
`(general-define-keys
|
|
#:prefix \"r\" #:wk \"Rofi\"
|
|
(\"p\" (exec \"~/.config/rofi/bin/password-manager\"))))"
|
|
|
|
(when parent-prefix
|
|
(set! prefix (string-append parent-prefix " " prefix)))
|
|
|
|
(when prefix
|
|
(format #t "define prefix submap: ~a, wk ~a\n" prefix wk)
|
|
(general-define-key prefix #:submap wk))
|
|
|
|
(map (lambda (arg)
|
|
(when (list? arg)
|
|
(if (and
|
|
(symbol? (car arg))
|
|
(equal? "general-define-keys" (symbol->string (car arg))))
|
|
(apply general-define-keys (append `(#:parent-prefix ,prefix) (cdr arg)))
|
|
(apply general-define-key
|
|
(cons (string-append
|
|
(if prefix (string-append prefix " ") "")
|
|
(car arg)) (cdr arg))))))
|
|
args))
|
|
|
|
(define (custom-exception-handler exc command-id payload)
|
|
"Exception handler for evaluating expressions from commander."
|
|
(format #t "An error occurd while executing the expression: ~a\n" (exp->string exc))
|
|
(format #t "command: ~a, payload: ~a\n" command-id payload))
|
|
|
|
;; add a hook to listen to received commands (usually from commander)
|
|
(add-hook! command-received-hook
|
|
(lambda (command-id payload)
|
|
(eval-string (json-string->scm payload))))
|