| 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 |
(provide 'em-rebind) |
|---|
| 26 |
|
|---|
| 27 |
(eval-when-compile (require 'esh-maint)) |
|---|
| 28 |
|
|---|
| 29 |
(defgroup eshell-rebind nil |
|---|
| 30 |
"This module allows for special keybindings that only take effect |
|---|
| 31 |
while the point is in a region of input text. By default, it binds |
|---|
| 32 |
C-a to move to the beginning of the input text (rather than just the |
|---|
| 33 |
beginning of the line), and C-p and C-n to move through the input |
|---|
| 34 |
history, C-u kills the current input text, etc. It also, if |
|---|
| 35 |
`eshell-confine-point-to-input' is non-nil, does not allow certain |
|---|
| 36 |
commands to cause the point to leave the input area, such as |
|---|
| 37 |
`backward-word', `previous-line', etc. This module intends to mimic |
|---|
| 38 |
the behavior of normal shells while the user editing new input text." |
|---|
| 39 |
:tag "Rebind keys at input" |
|---|
| 40 |
:group 'eshell-module) |
|---|
| 41 |
|
|---|
| 42 |
|
|---|
| 43 |
|
|---|
| 44 |
|
|---|
| 45 |
|
|---|
| 46 |
(defcustom eshell-rebind-load-hook '(eshell-rebind-initialize) |
|---|
| 47 |
"*A list of functions to call when loading `eshell-rebind'." |
|---|
| 48 |
:type 'hook |
|---|
| 49 |
:group 'eshell-rebind) |
|---|
| 50 |
|
|---|
| 51 |
(defcustom eshell-rebind-keys-alist |
|---|
| 52 |
'(([(control ?a)] . eshell-bol) |
|---|
| 53 |
([home] . eshell-bol) |
|---|
| 54 |
([(control ?d)] . eshell-delchar-or-maybe-eof) |
|---|
| 55 |
([backspace] . eshell-delete-backward-char) |
|---|
| 56 |
([delete] . eshell-delete-backward-char) |
|---|
| 57 |
([(control ?w)] . backward-kill-word) |
|---|
| 58 |
([(control ?u)] . eshell-kill-input)) |
|---|
| 59 |
"*Bind some keys differently if point is in input text." |
|---|
| 60 |
:type '(repeat (cons (vector :tag "Keys to bind" |
|---|
| 61 |
(repeat :inline t sexp)) |
|---|
| 62 |
(function :tag "Command"))) |
|---|
| 63 |
:group 'eshell-rebind) |
|---|
| 64 |
|
|---|
| 65 |
(defcustom eshell-confine-point-to-input t |
|---|
| 66 |
"*If non-nil, do not allow the point to leave the current input. |
|---|
| 67 |
This is more difficult to do nicely in Emacs than one might think. |
|---|
| 68 |
Basically, the `point-left' attribute is added to the input text, and |
|---|
| 69 |
a function is placed on that hook to take the point back to |
|---|
| 70 |
`eshell-last-output-end' every time the user tries to move away. But |
|---|
| 71 |
since there are many cases in which the point _ought_ to move away |
|---|
| 72 |
\(for programmatic reasons), the variable |
|---|
| 73 |
`eshell-cannot-leave-input-list' defines commands which are affected |
|---|
| 74 |
from this rule. However, this list is by no means as complete as it |
|---|
| 75 |
probably should be, so basically all one can hope for is that other |
|---|
| 76 |
people will left the point alone in the Eshell buffer. Sigh." |
|---|
| 77 |
:type 'boolean |
|---|
| 78 |
:group 'eshell-rebind) |
|---|
| 79 |
|
|---|
| 80 |
(defcustom eshell-error-if-move-away t |
|---|
| 81 |
"*If non-nil, consider it an error to try to move outside current input. |
|---|
| 82 |
This is default behavior of shells like bash." |
|---|
| 83 |
:type 'boolean |
|---|
| 84 |
:group 'eshell-rebind) |
|---|
| 85 |
|
|---|
| 86 |
(defcustom eshell-remap-previous-input t |
|---|
| 87 |
"*If non-nil, remap input keybindings on previous prompts as well." |
|---|
| 88 |
:type 'boolean |
|---|
| 89 |
:group 'eshell-rebind) |
|---|
| 90 |
|
|---|
| 91 |
(defcustom eshell-cannot-leave-input-list |
|---|
| 92 |
'(beginning-of-line-text |
|---|
| 93 |
beginning-of-line |
|---|
| 94 |
move-to-column |
|---|
| 95 |
move-to-column-force |
|---|
| 96 |
move-to-left-margin |
|---|
| 97 |
move-to-tab-stop |
|---|
| 98 |
forward-char |
|---|
| 99 |
backward-char |
|---|
| 100 |
delete-char |
|---|
| 101 |
delete-backward-char |
|---|
| 102 |
backward-delete-char |
|---|
| 103 |
backward-delete-char-untabify |
|---|
| 104 |
kill-paragraph |
|---|
| 105 |
backward-kill-paragraph |
|---|
| 106 |
kill-sentence |
|---|
| 107 |
backward-kill-sentence |
|---|
| 108 |
kill-sexp |
|---|
| 109 |
backward-kill-sexp |
|---|
| 110 |
kill-word |
|---|
| 111 |
backward-kill-word |
|---|
| 112 |
kill-region |
|---|
| 113 |
forward-list |
|---|
| 114 |
backward-list |
|---|
| 115 |
forward-page |
|---|
| 116 |
backward-page |
|---|
| 117 |
forward-point |
|---|
| 118 |
forward-paragraph |
|---|
| 119 |
backward-paragraph |
|---|
| 120 |
backward-prefix-chars |
|---|
| 121 |
forward-sentence |
|---|
| 122 |
backward-sentence |
|---|
| 123 |
forward-sexp |
|---|
| 124 |
backward-sexp |
|---|
| 125 |
forward-to-indentation |
|---|
| 126 |
backward-to-indentation |
|---|
| 127 |
backward-up-list |
|---|
| 128 |
forward-word |
|---|
| 129 |
backward-word |
|---|
| 130 |
forward-line |
|---|
| 131 |
previous-line |
|---|
| 132 |
next-line |
|---|
| 133 |
forward-visible-line |
|---|
| 134 |
forward-comment |
|---|
| 135 |
forward-thing) |
|---|
| 136 |
"*A list of commands that cannot leave the input area." |
|---|
| 137 |
:type '(repeat function) |
|---|
| 138 |
:group 'eshell-rebind) |
|---|
| 139 |
|
|---|
| 140 |
|
|---|
| 141 |
|
|---|
| 142 |
(defvar eshell-input-keymap) |
|---|
| 143 |
(defvar eshell-previous-point) |
|---|
| 144 |
(defvar eshell-lock-keymap) |
|---|
| 145 |
|
|---|
| 146 |
|
|---|
| 147 |
|
|---|
| 148 |
(defun eshell-rebind-initialize () |
|---|
| 149 |
"Initialize the inputing code." |
|---|
| 150 |
(unless eshell-non-interactive-p |
|---|
| 151 |
(add-hook 'eshell-mode-hook 'eshell-setup-input-keymap nil t) |
|---|
| 152 |
(make-local-variable 'eshell-previous-point) |
|---|
| 153 |
(add-hook 'pre-command-hook 'eshell-save-previous-point nil t) |
|---|
| 154 |
(make-local-variable 'overriding-local-map) |
|---|
| 155 |
(add-hook 'post-command-hook 'eshell-rebind-input-map nil t) |
|---|
| 156 |
(set (make-local-variable 'eshell-lock-keymap) nil) |
|---|
| 157 |
(define-key eshell-command-map [(meta ?l)] 'eshell-lock-local-map))) |
|---|
| 158 |
|
|---|
| 159 |
(defun eshell-lock-local-map (&optional arg) |
|---|
| 160 |
"Lock or unlock the current local keymap. |
|---|
| 161 |
Within a prefix arg, set the local keymap to its normal value, and |
|---|
| 162 |
lock it at that." |
|---|
| 163 |
(interactive "P") |
|---|
| 164 |
(if (or arg (not eshell-lock-keymap)) |
|---|
| 165 |
(progn |
|---|
| 166 |
(use-local-map eshell-mode-map) |
|---|
| 167 |
(setq eshell-lock-keymap t) |
|---|
| 168 |
(message "Local keymap locked in normal mode")) |
|---|
| 169 |
(use-local-map eshell-input-keymap) |
|---|
| 170 |
(setq eshell-lock-keymap nil) |
|---|
| 171 |
(message "Local keymap unlocked: obey context"))) |
|---|
| 172 |
|
|---|
| 173 |
(defun eshell-save-previous-point () |
|---|
| 174 |
"Save the location of point before the next command is run." |
|---|
| 175 |
(setq eshell-previous-point (point))) |
|---|
| 176 |
|
|---|
| 177 |
(defsubst eshell-point-within-input-p (pos) |
|---|
| 178 |
"Test whether POS is within an input range." |
|---|
| 179 |
(let (begin) |
|---|
| 180 |
(or (and (>= pos eshell-last-output-end) |
|---|
| 181 |
eshell-last-output-end) |
|---|
| 182 |
(and eshell-remap-previous-input |
|---|
| 183 |
(setq begin |
|---|
| 184 |
(save-excursion |
|---|
| 185 |
(eshell-bol) |
|---|
| 186 |
(and (not (bolp)) (point)))) |
|---|
| 187 |
(>= pos begin) |
|---|
| 188 |
(<= pos (line-end-position)) |
|---|
| 189 |
begin)))) |
|---|
| 190 |
|
|---|
| 191 |
(defun eshell-rebind-input-map () |
|---|
| 192 |
"Rebind the input keymap based on the location of the cursor." |
|---|
| 193 |
(ignore-errors |
|---|
| 194 |
(unless eshell-lock-keymap |
|---|
| 195 |
(if (eshell-point-within-input-p (point)) |
|---|
| 196 |
(use-local-map eshell-input-keymap) |
|---|
| 197 |
(let (begin) |
|---|
| 198 |
(if (and eshell-confine-point-to-input |
|---|
| 199 |
(setq begin |
|---|
| 200 |
(eshell-point-within-input-p eshell-previous-point)) |
|---|
| 201 |
(memq this-command eshell-cannot-leave-input-list)) |
|---|
| 202 |
(progn |
|---|
| 203 |
(use-local-map eshell-input-keymap) |
|---|
| 204 |
(goto-char begin) |
|---|
| 205 |
(if (and eshell-error-if-move-away |
|---|
| 206 |
(not (eq this-command 'kill-region))) |
|---|
| 207 |
(beep))) |
|---|
| 208 |
(use-local-map eshell-mode-map))))))) |
|---|
| 209 |
|
|---|
| 210 |
(defun eshell-setup-input-keymap () |
|---|
| 211 |
"Setup the input keymap to be used during input editing." |
|---|
| 212 |
(make-local-variable 'eshell-input-keymap) |
|---|
| 213 |
(setq eshell-input-keymap (make-sparse-keymap)) |
|---|
| 214 |
(set-keymap-parent eshell-input-keymap eshell-mode-map) |
|---|
| 215 |
(let ((bindings eshell-rebind-keys-alist)) |
|---|
| 216 |
(while bindings |
|---|
| 217 |
(define-key eshell-input-keymap (caar bindings) |
|---|
| 218 |
(cdar bindings)) |
|---|
| 219 |
(setq bindings (cdr bindings))))) |
|---|
| 220 |
|
|---|
| 221 |
(defun eshell-delete-backward-char (n &optional killflag) |
|---|
| 222 |
"Delete the last character, unless it's part of the output." |
|---|
| 223 |
(interactive "P") |
|---|
| 224 |
(let ((count (prefix-numeric-value n))) |
|---|
| 225 |
(if (eshell-point-within-input-p (- (point) count)) |
|---|
| 226 |
(delete-backward-char count n) |
|---|
| 227 |
(beep)))) |
|---|
| 228 |
|
|---|
| 229 |
(defun eshell-delchar-or-maybe-eof (arg) |
|---|
| 230 |
"Delete ARG characters forward or send an EOF to subprocess. |
|---|
| 231 |
Sends an EOF only if point is at the end of the buffer and there is no |
|---|
| 232 |
input." |
|---|
| 233 |
(interactive "p") |
|---|
| 234 |
(let ((proc (eshell-interactive-process))) |
|---|
| 235 |
(if (eobp) |
|---|
| 236 |
(cond |
|---|
| 237 |
((/= (point) eshell-last-output-end) |
|---|
| 238 |
(beep)) |
|---|
| 239 |
(proc |
|---|
| 240 |
(process-send-eof)) |
|---|
| 241 |
(t |
|---|
| 242 |
(eshell-life-is-too-much))) |
|---|
| 243 |
(eshell-delete-backward-char (- arg))))) |
|---|
| 244 |
|
|---|
| 245 |
|
|---|
| 246 |
|
|---|
| 247 |
|
|---|
| 248 |
|
|---|
| 249 |
|
|---|