1;;; em-rebind.el --- rebind keys when point is at current input 2 3;; Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 4;; 2005, 2006, 2007 Free Software Foundation, Inc. 5 6;; Author: John Wiegley <johnw@gnu.org> 7 8;; This file is part of GNU Emacs. 9 10;; GNU Emacs is free software; you can redistribute it and/or modify 11;; it under the terms of the GNU General Public License as published by 12;; the Free Software Foundation; either version 2, or (at your option) 13;; any later version. 14 15;; GNU Emacs is distributed in the hope that it will be useful, 16;; but WITHOUT ANY WARRANTY; without even the implied warranty of 17;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18;; GNU General Public License for more details. 19 20;; You should have received a copy of the GNU General Public License 21;; along with GNU Emacs; see the file COPYING. If not, write to the 22;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 23;; Boston, MA 02110-1301, USA. 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 31while the point is in a region of input text. By default, it binds 32C-a to move to the beginning of the input text (rather than just the 33beginning of the line), and C-p and C-n to move through the input 34history, C-u kills the current input text, etc. It also, if 35`eshell-confine-point-to-input' is non-nil, does not allow certain 36commands to cause the point to leave the input area, such as 37`backward-word', `previous-line', etc. This module intends to mimic 38the behavior of normal shells while the user editing new input text." 39 :tag "Rebind keys at input" 40 :group 'eshell-module) 41 42;;; Commentary: 43 44;;; User Variables: 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. 67This is more difficult to do nicely in Emacs than one might think. 68Basically, the `point-left' attribute is added to the input text, and 69a 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 71since 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 74from this rule. However, this list is by no means as complete as it 75probably should be, so basically all one can hope for is that other 76people 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. 82This 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;; Internal Variables: 141 142(defvar eshell-input-keymap) 143(defvar eshell-previous-point) 144(defvar eshell-lock-keymap) 145 146;;; Functions: 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. 161Within a prefix arg, set the local keymap to its normal value, and 162lock 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. 231Sends an EOF only if point is at the end of the buffer and there is no 232input." 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;;; Code: 246 247;;; arch-tag: 76d84f12-cc56-4d67-9b7d-c6b44ad20530 248;;; em-rebind.el ends here 249