Emacs: Keybinding to TAB breaks autocompletion in

2019-07-04 17:14发布

Simply put, I just set a keybinding on the TAB key, but now when I push TAB in the minibuffer to auto-complete a command, it fails with the following message: The mark is not set now, so there is no region.

In other words, I only need my TAB keybinding when my cursor is in the buffer (not the minibuffer).

In my example below, how can I set my tab to indent when I am in text/fundamental mode in the buffer without losing autocompletion while in the mini-buffer? I have the following functions and key-bindings:

;; Shift the selected region right if distance is postive, left if
;; negative

 (defun shift-region (distance)
   (let ((mark (mark)))
     (save-excursion
       (indent-rigidly (region-beginning) (region-end) distance)
       (push-mark mark t t)
       ;; Tell the command loop not to deactivate the mark
       ;; for transient mark mode
       (setq deactivate-mark nil))))

(defun shift-right ()
  (interactive)
  (shift-region 2))

(defun shift-left ()
  (interactive)
  (shift-region -2))

;; Bind (shift-right) and (shift-left) function to your favorite keys. I use
;; the following so that Ctrl-Shift-Right Arrow moves selected text one 
;; column to the right, Ctrl-Shift-Left Arrow moves selected text one
;; column to the left:

;; (global-set-key [C-S-right] 'shift-right)
;; (global-set-key [C-S-left] 'shift-left)
(global-set-key [tab] 'shift-right)
(global-set-key [backtab] 'shift-left)

3条回答
爱情/是我丢掉的垃圾
2楼-- · 2019-07-04 17:46

In addition to what others have said:

  1. The TAB key is typically not the same as <tab>, which is what you are using by specifying [tab]. The TAB key is the same as C-i, and you can use (kbd "TAB") to bind it.

  2. You can, if you want to, go ahead and bind TAB to your command in the global-map, as you have done, but then override that for the minibuffer by rebinding it in each of the minibuffer keymaps to whatever commands you like for them.

    For example, if you want the usual minibuffer bindings for TAB, then do this:

    1. Start Emacs using emacs -Q (no init file).

    2. Optionally load any library that makes a non-default minibuffer binding for TAB (e.g. autocomplete?).

    3. Load library help-fns+.el, to obtain command describe-keymap, bound globally to C-h M-k.

    4. Use C-h M-k to check the binding of TAB in each of the minibuffer keymaps used by your version of Emacs. This will include minibuffer-local-map, minibuffer-local-completion-map, and minibuffer-local-must-match-map, and it may include some more. See (elisp) Completion Commands for the list of minibuffer keymap variables.

      For example, C-h M-k minibuffer-local-completion-map shows you the bindings in that keymap. Look for TAB in the list.

      (If you don't want to download help-fns+.el then you can use lookup-key. That library just makes listing the keys in a keymap easy.)

    5. Bind TAB to that default binding, in your init file, after having bound it globally to your non minibuffer-oriented command. IOW, restore the minibuffer bindings as they should be.

查看更多
女痞
3楼-- · 2019-07-04 17:48

The problem is simply that you bound your command to [tab] rather than to "\t". tab denotes the TAB key under GUIs, but under a tty Emacs instead receives a TAB character (i.e. ?\t), so when you hit tab Emacs first looks for a tab binding and if there isn't any, a function-key-map remapping turns it into a ?\t and tries again. The minibuffer only binds "\t", so any global binding to [tab] will take precedence.

In short, use (global-set-key "\t" 'shift-right) and this problem will disappear.

查看更多
唯我独甜
4楼-- · 2019-07-04 17:51

You can check whether you are in a minibuffer by using the function window-minibuffer-p. From the documentation

Return non-nil if WINDOW is a minibuffer window.
WINDOW must be a valid window and defaults to the selected one.

Also emacs 24.4 already provides the things you want to achieve in the functions above. The command indent-rigidly has been enhanced such that you can indent the regions using left, right, tab and shift-tab keys.

You can select the region you want to indent and hit C-xtab after which you will be able to move the region by one space using the right and left keys. You can also move the selected region by one tab space using the tab and shift-tab keys, it is really convenient since the keybindings above remain active until you press any other key.

查看更多
登录 后发表回答