1

I am working on a very old Emacs version (23.2.1). I am trying to bind C-C C-i to an interactive command without luck.

The command selects code regions delimited between two lines that start with ##. It works well when I call it interactively (M-x python-select-cell), but the keybinding does not work in Python buffers:

(defun python-inside-comment-p ()
  (save-excursion
    (beginning-of-line 1)
    (looking-at "^#")))

(defun python-select-cell ()
  (interactive)
  (goto-char
   (if (re-search-backward "^\\s-*##[^#]" nil t)
       (match-end 0)
     (point-min)))
  (while (and (python-inside-comment-p)
              (eq 0 (forward-line 1)))
    nil)
  (set-mark (point))
  (goto-char
   (if (re-search-forward "^\\s-*\\(##[^#]\\)" nil t)
       (- (match-beginning 1) 2)
     (point-max))))

Global keybinding:

# Binding
(global-set-key (kbd "C-c C-i") 'python-select-cell)

I have also tried setting up a hook without luck

(add-hook 'python-mode-hook
    #'(lambda ()
          (global-set-key (kbd "C-C C-i") 'python-select-cell)))

What could be going on?

5

Modes can define their own key bindings (and most do). Key bindings defined by a mode hide global bindings. Python mode binds C-c C-i (to python-find-imports), so its binding hides yours. This is explained in more detail in the manual in the section on local keymaps.

You can check what a key does in the current context (e.g. in the current mode) by pressing C-h c (describe-key-briefly) or C-h k (describe-key) then typing the key (or key sequence). There's no easy way to look up where a particular binding was made, but you can list the bindings made by the current major mode and active minor modes with C-h m (describe-mode).

There are conventions for key bindings in Emacs. I can't find them in the Emacs manual, they're buried in the Elisp manual under major mode conventions: C-c is the prefix that is left free in Emacs; C-c C-letter is conventionally for major modes, and C-c letter is conventionally for the end-user. As the end-user, expect major modes to often override C-c C-letter bindings.

If you want your command to be bound globally, you should bind a different key, such as C-c i.

If you want your command to be bound only in Python mode, you need to define it in the Python mode keymap, python-mode-map. The keymap doesn't exist until Python mode is loaded, so you need to delay until this happens. Use eval-after-load (or the with-eval-after-load wrapper in recent versions of Emacs):

(defun josh-after-load-python ()
  (define-key python-mode-map (kbd "C-c C-i") 'python-select-cell))
(eval-after-load "python" '(josh-after-load-python))

This will, of course, shadow the binding for python-find-imports. If you care about that command, you may want to pick a different key.

  • Perfect. Super helpful, right the point, and solved the problem. – Josh Jun 7 '16 at 19:56

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.