Search code examples
emacselisplazy-loadingkey-bindings

Eval form after symbol has been defined


I have a function permanent-set-key that automates adding key-binding definitions, both local and global, to an init file. When the user requests to add a local key-binding, the function determines the current local keymap using this pretty robust approach from the answer to a question I asked earlier.

So now I know the symbol-name of the (current-local-map) and have the appropriate sexp that will define the desired key, for example:

(define-key python-shell-map [3 6] 'python-describe-symbol)

However, at the time of initialization, usually such maps are undefined, so eagerly evaluating the form above will cause error.

What is a robust programmatic approach to scheduling these forms to be eval-ed at the appropriate time?

What I have been doing so far has been to assume a minor mode exists for the current local map, and then guess the name of the minor mode's file in order to wrap the above sexp in an eval-after-load form, according to the convention foo-mode-mode-map. For example, this was generated automatically:

(eval-after-load 'dired '(define-key dired-mode-map [8388711] 'run_gdmap_dired))

and happens to work (since there does indeed exist a dired mode and file).

For the first example, this approach does not work: there does not exist a python-shell minor or major mode. The major mode comint-mode handles several "sub-modes" so adding to it customizations desired for only the "python" version does not seem appropriate.

How can I determine the name of the file which will define a symbol such as python-shell-map?

I suppose I could use after-load-functions and check for all new symbols that may have been defined, but maybe there is a more direct solution.


Solution

  • I just found my own answer, thanks to an apropos that I hadn't noticed earlier:

    (symbol-file SYMBOL &optional TYPE)
    
    
    
    For more information check the manuals.
    
    Return the name of the file that defined SYMBOL.
    The value is normally an absolute file name.  It can also be nil,
    if the definition is not associated with any file.  If SYMBOL
    specifies an autoloaded function, the value can be a relative
    file name without extension.
    
    If TYPE is nil, then any kind of definition is acceptable.  If
    TYPE is `defun', `defvar', or `defface', that specifies function
    definition, variable definition, or face definition only.
    
    [back]
    

    So this works:

    (symbol-file 'python-shell-map)--> "/usr/share/emacs/23.3/lisp/progmodes/python.elc"
    

    Edit:

    Just to make this more explicit:

    (format "(eval-after-load \"%s\" '%s)" (symbol-file keymap-symbol) define-key-sexp)