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?

Scott Weldon
  • 2,695
  • 1
  • 18
  • 31
Josh
  • 113
  • 6

1 Answers1

6

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.