;;; -*- lexical-binding: t -*- ;; ---------------- rekado minor mode -------------------- (defvar rekado-permanent-mode-q nil "indicates whether permanent keys are active") (defvar rekado-mode-map (make-sparse-keymap) "keymap for rekado-mode") (defun rekado-mode-define-keys (define-permanent-keys) "Defines key bindings for rekado-mode. If the argument is t, the edit mode keys will be bound as well." ;; return a command that will enable transient-mark-mode if it isn't ;; yet active before running the command `cmd` (cl-labels ((transient-wrap (cmd) (lambda () (interactive) (unless (and transient-mark-mode mark-active) (set-mark-command nil) (setq transient-mark-mode '(only . ,transient-mark-mode))) (funcall cmd)))) (let* ((modal-keys `(("a" . move-beginning-of-line) ("e" . move-end-of-line) ;; define JKLI (HTNC in Dvorak) as arrow keys ("c" . previous-line) ("t" . next-line) ("h" . backward-char) ("n" . forward-char) ;; add meta key to move more quickly ("M-c" . (lambda () (interactive) (previous-line 5))) ("M-t" . (lambda () (interactive) (next-line 5))) ("M-h" . backward-word) ("M-n" . forward-word) ;; make shifted arrows work with transient-mark-mode ("C" . ,(transient-wrap 'previous-line)) ("T" . ,(transient-wrap 'next-line)) ("H" . ,(transient-wrap 'backward-char)) ("N" . ,(transient-wrap 'forward-char)) ("M-C" . ,(transient-wrap '(lambda () (interactive) (previous-line 5)))) ("M-T" . ,(transient-wrap '(lambda () (interactive) (next-line 5)))) ("M-H" . ,(transient-wrap 'backward-word)) ("M-N" . ,(transient-wrap 'forward-word)) ;; define U/O (G/R in Dvorak) to kill word in direction ("G" . backward-kill-word) ("R" . kill-word) ;; jump to character ("f" . ace-jump-char-mode) ("i" . rekado-permanent-mode-exit) ("k" . (lambda () (interactive) (move-beginning-of-line nil) (kill-whole-line))) ;; undo as in vim ("u" . undo) ;; repeat as in vim ("." . repeat) ;; paste as in vim ("p" . (lambda () (interactive) (next-line) (beginning-of-line) (yank))) ("P" . (lambda () (interactive) (beginning-of-line) (yank))) ;; TODO: replace single character as in vim ;;("r" . forward-word) ;; copy as in vim ("y" . kill-ring-save) ("s" . isearch-forward-regexp) ;; open line below/above as in vim ("o" . (lambda () (interactive) (open-line-below) (rekado-permanent-mode-exit))) ("O" . (lambda () (interactive) (open-line-above) (rekado-permanent-mode-exit))) ;; join lines (like J in vim) ("j" . (lambda () (interactive) (join-line -1))) ;; change till the end of the line ("R" . (lambda () (interactive) (kill-line) (rekado-permanent-mode-exit))) ("<" . beginning-of-buffer) (">" . end-of-buffer) ))) (progn ;; toggle permanent mode (define-key rekado-mode-map (kbd "") 'rekado-permanent-mode-toggle) ;; toggle permanent mode (define-key rekado-mode-map (kbd "") 'rekado-permanent-mode-toggle) (if define-permanent-keys ;; define permanent keys (progn (setq rekado-permanent-mode-q t) (mapc (lambda (pair) (define-key rekado-mode-map (kbd (car pair)) (cdr pair))) modal-keys)) ;; undefine permanent keys (progn (setq rekado-permanent-mode-q nil) (mapc (lambda (pair) (define-key rekado-mode-map (kbd (car pair)) nil)) modal-keys)))))) rekado-mode-map) (defun open-line-below () (interactive) (end-of-line) (newline) (indent-for-tab-command)) (defun open-line-above () (interactive) (beginning-of-line) (newline) (forward-line -1) (indent-for-tab-command)) (defun rekado-permanent-mode-exit () (interactive) (set-cursor-color "White") (rekado-mode-define-keys nil)) (defun rekado-permanent-mode-toggle () (interactive) (if rekado-permanent-mode-q (rekado-permanent-mode-exit) (progn (set-cursor-color "Red") (rekado-mode-define-keys 1)))) ;; disable permanent keys when in the minibuffer (also when running ;; commands such as isearch) (add-hook 'post-command-hook (lambda () (if (minibufferp) (rekado-permanent-mode-exit)))) (define-minor-mode rekado-mode "Cursor movement shortcuts while Alt is hold and editing shortcuts when permanent mode is active." :lighter " rekado" :global t :keymap rekado-mode-map :after-hook (rekado-mode-define-keys nil)) (provide 'rekado-mode)