;;; bespoke vish modal -*- lexical-binding: t; -*- (require 's) (defun do-nothing () (interactive)) (defun yank-looks-like-lines () (s-contains? " " (current-kill 0 t))) (defun paste-after-maybe-lines () (interactive) (if (yank-looks-like-lines) (progn (move-end-of-line nil) (newline) (yank)) (forward-char-unless-eol) (yank))) (defun paste-before-maybe-lines () (interactive) (if (yank-looks-like-lines) (progn (move-beginning-of-line nil) (yank)) (yank))) (defun forward-char-unless-eol (&optional arg) (interactive "P") (when (< (point) (point-at-eol)) (forward-char arg))) (defun mark-end-of-line (&optional arg) (interactive "P") (push-mark) (move-end-of-line arg) (exchange-point-and-mark)) (defun mark-beginning-of-line (&optional arg) (interactive "P") (push-mark) (move-beginning-of-line arg) (exchange-point-and-mark)) ;; what I really want is a meta operator to invert the arg count, ;; but between how ryo calls functions and expects symbols in binds, ;; this is the best I can do. (defun mark-word-backward (&optional arg allow-extend) (interactive "P\np") (cond ((null arg) (setq arg -1)) ((numberp arg) (setq arg (* -1 arg)))) (mark-word arg allow-extend)) (defun mark-sexp-backward (&optional arg allow-extend) (interactive "P\np") (cond ((null arg) (setq arg -1)) ((numberp arg) (setq arg (* -1 arg)))) (mark-sexp arg allow-extend)) (defun mark-defun-backward (&optional arg interactive) (interactive "p\nd") (cond ((null arg) (setq arg -1)) ((numberp arg) (setq arg (* -1 arg)))) (mark-defun arg interactive)) (defun mark-paragraph-backward (&optional arg allow-extend) (interactive "P\np") (cond ((null arg) (setq arg -1)) ((numberp arg) (setq arg (* -1 arg)))) (mark-paragraph arg allow-extend)) (defconst my/ryo-digits '(("1" "C-1" :norepeat t) ("2" "C-2" :norepeat t) ("3" "C-3" :norepeat t) ("4" "C-4" :norepeat t) ("5" "C-5" :norepeat t) ("6" "C-6" :norepeat t) ("7" "C-7" :norepeat t) ("8" "C-8" :norepeat t) ("9" "C-9" :norepeat t))) (defconst my/ryo-moves '(("h" backward-char) ("j" next-line) ("k" previous-line) ("l" forward-char) ("e" forward-word) ("b" backward-word) ("E" forward-sexp) ("B" backward-sexp) ("0" "C-a") ("$" "C-e") ("[" beginning-of-defun) ("]" end-of-defun) ("{" backward-paragraph) ("}" forward-paragraph) )) (defconst my/ryo-marking-moves '(("h" backward-char :first (push-mark-command)) ("j" next-line :first (push-mark-command)) ("k" previous-line :first (push-mark-command)) ("l" forward-char :first (push-mark-command)) ("b" mark-word-backward) ("e" mark-word) ("B" mark-sexp-backward) ("E" mark-sexp) ("[" mark-defun-backward) ("]" mark-defun) ("0" mark-beginning-of-line) ("$" mark-end-of-line) ("{" mark-paragraph-backward) ("}" mark-paragraph) )) (defconst my/ryo-no-ops '( "" "`" "-" "+" "q" "w" "r" "t" "\\" "s" "f" ";" "'" "z" "n" "m" "," "." "~" "!" "@" "#" "%" "^" "&" "*" "(" ")" "_" "+" "Q" "W" "R" "T" "Y" "U" "|" "S" "D" "F" "H" "J" "K" "L" ":" "\"" "Z" "X" "C" "V" "N" "M" "<" ">" )) (use-package ryo-modal :demand t :bind (:map my/keys-mode-map ("C-c C-" . ryo-modal-mode)) :config (define-minor-mode my/temp-nonmodal-mode "Minor mode for a temporary exit that should return to ryo-modal-mode." :keymap (define-keymap "" 'my/temp-nonmodal-mode) :lighter " " (ryo-modal-mode (if my/temp-nonmodal-mode -1 1))) (let* () (eval `(ryo-modal-keys ,@my/ryo-moves ,@my/ryo-digits ,@(mapcar (lambda (key) (list key 'do-nothing)) my/ryo-no-ops) ("g" (("g" beginning-of-buffer))) ("G" end-of-buffer) ("i" my/temp-nonmodal-mode) ("I" back-to-indentation :then '(my/temp-nonmodal-mode)) ("a" forward-char-unless-eol :then '(my/temp-nonmodal-mode)) ("A" move-end-of-line :then '(my/temp-nonmodal-mode)) ("o" move-end-of-line :then '(newline-and-indent my/temp-nonmodal-mode)) ("O" move-beginning-of-line :then '(open-line indent-according-to-mode my/temp-nonmodal-mode)) ("x" delete-char) ("d" (("d" kill-whole-line) ("m" kill-region))) ("d" ,my/ryo-marking-moves :then '(kill-region)) ("c" (("c" kill-whole-line)) :then '(open-line my/temp-nonmodal-mode)) ("c" (("m" kill-region)) :then '(my/temp-nonmodal-mode)) ("C" kill-line :then '(my/temp-nonmodal-mode)) ("c" ,my/ryo-marking-moves :then '(kill-region my/temp-nonmodal-mode)) ("y" (("m" copy-region-as-kill))) ("y" (("y" copy-region-as-kill)) :first '(push-mark move-beginning-of-line push-mark move-end-of-line forward-char) :then '(pop-mark pop-to-mark-command)) ("P" paste-before-maybe-lines) ("p" paste-after-maybe-lines) ("/" isearch-forward-regexp) ("?" isearch-backward-regexp) ("u" undo) ("SPC" set-mark-command) ("v" set-mark-command) ))) (setq ryo-modal-cursor-color "aquamarine") (defun ryo-modal-unless-minibuffer () (unless (minibufferp) (ryo-modal-mode 1))) ;; (add-hook 'after-change-major-mode-hook 'ryo-modal-unless-minibuffer) )