Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I bind C-= in emacs?

This s-expression in my .emacs file does not produce the desired result:

(define-key global-map (kbd "C-=") 'djhaskin987-untab-to-tab-stop)

Why can't I bind a command to Ctrl+=?

EDIT for clarification:

I am using emacs23-nox on the standard build of urxvt-256colors for Debian, except that I have recompiled with --disable-iso405776 (or something to that effect) it so that Ctrl+Shift doesn't do the weird 'insert character' thing. I don't know if this affects anything. For example, C-M-i sends M-TAB, which I don't understand.

EDIT II:

I apologize for not making this clear. The function djhaskin987-untab-to-tab-stop has the line (interactive) in it. This part works.

like image 223
djhaskin987 Avatar asked May 18 '12 21:05

djhaskin987


4 Answers

The accepted answer in combination with the link in the first comment to it is enough to get started on a complete solution. The steps are:

  1. make your terminal output escape codes for the key
  2. make Emacs recognise the escape codes as a standard keypress
  3. bind the keypress in a mode map

The first is very terminal and/or operating system dependent.

The link in the first comment shows some examples for X Window System. The key names are available in /usr/X11R6/include/X11/keysymdef.h (or try locate keysymdef.h), prefixed with XK_ (which should be removed for our purposes). I read that symbolic names are preferred over key literals.

I don't currently run X but I think it should look like this in your case:

XTerm.VT100.Translations: #override \
Ctrl ~Meta ~Shift  <Key> equal:         string(0x1b) string("[emacs-C-=")\n

The first string is the escape, the second is of your choosing.

In iTerm you can use Preferences->Keys and choose Send Escape Sequence as the Action. For example, I have:

iTerm key mappings

Emacs Wiki lists some configuration methods for other terminals.

Now you can teach Emacs to recognize it as a C-=. First define-key into input-decode-map. I have a couple of helper functions:

(defun my/global-map-and-set-key (key command &optional prefix suffix)
   "`my/map-key' KEY then `global-set-key' KEY with COMMAND.
 PREFIX or SUFFIX can wrap the key when passing to `global-set-key'."
   (my/map-key key)
   (global-set-key (kbd (concat prefix key suffix)) command))

 (defun my/map-key (key)
   "Map KEY from escape sequence \"\e[emacs-KEY\."
   (define-key function-key-map (concat "\e[emacs-" key) (kbd key)))

So then:

(my/global-map-and-set-key "C-=" 'some-function-to-bind-to)

Some keys (currently: ()\|;'`"#.,) will need escaping in the string, like C-\..

like image 194
Sam Brightman Avatar answered Nov 15 '22 11:11

Sam Brightman


In a terminal, TAB is represented by the same byte sequence as C-i. And typically the terminal has no special byte-sequence for C-=, so it will just send a =. There is nothing that Emacs can do about it. But you might be able to teach your terminal emulator to send some special byte sequence of your choice (check the documentation of your terminal emulator for that), after which you can teach Emacs to recognize it as a C-= (with something like (define-key input-decode-map "...thebytes..." [?\C-=])).

like image 25
Stefan Avatar answered Nov 15 '22 11:11

Stefan


The problem is that you use emacs in the terminal. The terminal does not allow "C-=". Try your function in the graphical emacs and it will work. You will have to find another keybinding for the terminal.

like image 31
Nicolas Dudebout Avatar answered Nov 15 '22 11:11

Nicolas Dudebout


You can map C-= using the default ascii codes: ^[[61;5u. Then you can bind it in Emacs either using:

(global-set-key (kbd "C-=") 'djhaskin987-untab-to-tab-stop))

or let use-package do it, e.g.:

(use-package expand-region
  :ensure t
  :bind (("C-=" . er/expand-region)))

I do want to thank Sam Brightman, for his wonderful solution. It's a very clean, albeit heavy-handed, approach that will work for any keys that cannot be sent via normal ascii codes. I've been wanting to get C-TAB working inside iterm2 for a long time. I was able to do it by deleting the builtin preferences keys for C-TAB/C-S-TAB and using his approach. With the following, I can be ssh'd into remote Linux boxes and quickly switch through lots of open buffers in projects, just like a desktop editor. enter image description here

(use-package nswbuff
  :defer 1
  :after (projectile)
  :commands (nswbuff-switch-to-previous-buffer
             nswbuff-switch-to-next-buffer)
  :config
  (progn
    (my/global-map-and-set-key "C-TAB" 'nswbuff-switch-to-previous-buffer)
    (my/global-map-and-set-key "C-S-TAB" 'nswbuff-switch-to-next-buffer))
  :init
  (setq nswbuff-display-intermediate-buffers t
        nswbuff-exclude-buffer-regexps '("^ "
                                         "^\*.*\*"
                                         "\*Treemacs.*\*"
                                         "^magit.*:.+")
        nswbuff-include-buffer-regexps '("^*Org Src")
        nswbuff-start-with-current-centered t
        nswbuff-buffer-list-function '(lambda ()
                                        (interactive)
                                        (if (projectile-project-p)
                                            (nswbuff-projectile-buffer-list)
                                          (buffer-list)))))
like image 44
user503582 Avatar answered Nov 15 '22 11:11

user503582