Stack Exchange
Emacs keybinding not working in custom major mode
I'm in the early stages of creating a major mode for Emacs for browsing and interacting with the Stack Exchange Network.
Involved in it are several major modes, all with one-key keybindings similar to dired.  I looked at the source for dired, and extracted what I thought would work:
(defvar stack-network-mode-map
  (let ((map (make-keymap)))
    (define-key map "n"     'stack-network-next-site)
    (define-key map "p"     'stack-network-previous-site)
    (define-key map ","     'stack-network-move-site-up)
    (define-key map "."     'stack-network-move-site-down)
    (define-key map "j"     'stack-network-jump-to-bookmarks)
    (define-key map "\C-m"  'stack-network-do-enter-site) ; ret
    (define-key map "o"     'stack-network-do-enter-site)
    (define-key map "u"     'stack-network-do-profile-summary)
    (define-key map "\C-uu" 'stack-network-do-profile-summary-for-user)
    (define-key map "i"     'stack-network-do-inbox)
    (define-key map "b"     'stack-network-toggle-bookmark)
    (define-key map "?"     'stack-network-list-functions) ; [1]
    (define-key map "\C-i"  'stack-network-display-details) ; tab
    map)
  "Keymap for Stack Exchange: Network Browser major mode")

but unfortunately this seems to have absolutely no effect; the buffer is simply edited just as any other normal buffer would be.  How can I achieve single-key keybindings if this isn't they way? (Which, by the way, I'm sure it is.  There has to be something else going on here.)

Need more detail.... I load the package you refer to, and it works just fine.  All the major mode bindings are available (though undefined).

Don't define major modes with defun.  Use define-derived-mode, which handles all the boilerplate for you, including killing local variables, switching the key map, setting major mode vars, running the hooks, etc.

You want to define stack-network-mode using define-derived-mode (and make it derive from special-mode, for example).
Other comments about your code:

use () rather than nil for empty argument lists.
stack-network-next-site needs to have (interactive) right after the docstring to make it an interactive command otherwise it won't work as a key-binding.

If you don't want to use special-mode, you can call supress-keymap right after creating your make-keymap.

This does prevent buffer editing (thanks to special-mode, I presume), but the keys are still not being bound :(  (Also, to my knowledge, () === nil.)

If you'd like to see the code as it stands, it's here (specific commit linked to preserve use for future reference)

@vermiculus () === nil holds, but it is convention to use () for empty argument lists.  nil at this place looks disturbing to most Emacs Lisp programmers.

@lunaryorn I'll keep that in mind -- I've mostly used it because it is much faster for me to type, and the idea of 'nil arguments' still makes sense.  But if it's convention we're after, I suppose I'll oblige.  I'm still stuck though; see the first two comments.

Move the definition of stack-network-mode-map before the define-derived-mode form.  Otherwise define-derived-mode defines stack-network-mode-map implicitly with a newly created keymap. defvar however does not change the value of variables which are already set.

@lunaryorn, would you please edit that into the answer?  That's what fixed it for good!

@vermiculus I have added this as a new answer.

It's unfortunate then that all I can give you is an upvote there.

@vermiculus I do not care for votes and reputation on my answers.

@lunaryorn it's only fair.  This is as much part of the solution as the accepted answer -- I would not have easily put together the fact that defvar is a little silly and define-derived-mode had the behavior.  At its core, upvoting is a way of saying 'thanks.'

Move the definition of stack-network-mode-map before the definition of the mode. Otherwise define-derived-mode implicitly defines this variable, and defvar does not change the value of non-nil variables, so the map will be empty actually.
See Derived Modes:

The new mode has its own sparse keymap, named variant-map. define-derived-mode makes the parent mode's keymap the parent of the new map, unless variant-map is already set and already has a parent.


You have defined a keymap but you have not used it. The variable exists but does not capture any key events.
(use-local-map stack-network-mode-map)

