summaryrefslogtreecommitdiff
path: root/rekado-mode.el
blob: e7e4faa48e579c1922cb84fe217e3fc6fcd5c299 (about) (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
;;; -*- 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)

              ;; jump to character
              ("f" . ace-jump-char-mode)
              ("i" . rekado-permanent-mode-exit)
              ;; 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)))
              ;; 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)))
              )))
      (progn
        ;; toggle permanent mode
        (define-key rekado-mode-map
          (kbd "<C-return>")
          'rekado-permanent-mode-toggle)

        ;; toggle permanent mode
        (define-key rekado-mode-map
          (kbd "<M-SPC>")
          '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)