There is an emacs extension that build keys to very unhandy location and I reassign key bindings in my .emacs file just after loading extension. I've peeked into the extension code, it uses no variables or defcustoms that may be passed prior its loading.
I disable existing bindings with (define-key ... nil) at first, and rebind them after that.
The issue is that all prefix bindings chain remains to live and pollutes my keyboard settings.
How can I remove all empty (with no children registered) prefix key recursively?
update with example
Assume map is an empty sparse keymap.
(define-key map (kbd "C-c M-p b") 'do-first)
(define-key map (kbd "C-c M-p b f g") 'do-second)
(define-key map (kbd "C-c M-p b r s") 'do-third)
(define-key map (kbd "C-c M-p b r s") nil)
(define-key map (kbd "C-c M-p b f g") nil)
(define-key map (kbd "C-c M-p b") nil)
After that I'd like to use some kind of function like (clean-map map) to make map empty again.
Unfortunately, there is no simple solution.
(defun eab/delete-sublist (sublst lst)
(read (replace-regexp-in-string
(prin1-to-string sublst)
""
(prin1-to-string lst))))
(defun clean-map (target-map)
(let ((map target-map))
(cl-flet ((clean-keymaps
(event def)
(if (keymapp def)
(if (keymap-emptyp def)
(progn
(setq map
(eab/delete-sublist (cons event def) map))
(map-keymap 'clean-keymaps map))
(map-keymap 'clean-keymaps def)))))
(map-keymap 'clean-keymaps map)
map)))
(defun keymap-emptyp (keymap)
(if (keymapp keymap)
(if (or (and
(eq 2 (length keymap))
(not (cdr (cadr keymap))))
(equal keymap '(keymap)))
't
nil)
nil))
(keymap-emptyp '(keymap (110))) => t
(keymap-emptyp '(keymap)) => t
(keymap-emptyp '(keymap (110) (103 . do-second))) => nil
(setq test-map (make-sparse-keymap))
(define-key test-map (kbd "C-c M-p b f k") 'do-first)
(define-key test-map (kbd "C-c M-p b f g") 'do-second)
(define-key test-map (kbd "C-c M-p b r s n") 'do-third)
(define-key test-map (kbd "C-c M-p b r s n") nil)
Before: there are two recursive prefix bindings, "r" and "r s".
C-c M-p b f Prefix Command
C-c M-p b r Prefix Command
C-c M-p b r s Prefix Command
C-c M-p b f g do-second
C-c M-p b f k do-first
(setq test-map (clean-map test-map))
After: it's cleaned.
C-c M-p b f Prefix Command
C-c M-p b f g do-second
C-c M-p b f k do-first
If #phils got you right, and using his example, you can do this:
(global-set-key (kbd "C-c b") nil)
That way the empty prefix is cleared.
Related
I'm trying to get vimish-fold to work, and it does work. The problem is that I want to bind it to the menu key instead of the M key.
(progn
(define-prefix-command 'my-menu-key-map)
(define-key vimish-fold-mode (kdb "v f") 'vimish-fold)
(define-key vimish-fold-mode (kdb "v u") 'vimish-fold-refold)
)
(global-set-key (kdb "<menu>") my-menu-key-map)
I essentially want menu v f -> vimish-fold and menu v u -> vimish-fold-refold. The problem I'm having is it's giving me an error telling me I have the wrong type argument.
Error in private config: init.el, (wrong-type-argument keymapp nil)
You have some repeated typos:
(kdb should be (kbd
(define-key vimish-fold-mode should be (define-key my-menu-key-map
I have the following configuration for helm and helm-swoop in my Emacs init file:
(use-package helm
:demand t
:diminish helm-mode
:init
(progn
(require 'helm-config)
(setq helm-candidate-number-limit 100)
(setq helm-idle-delay 0.0
helm-input-idle-delay 0.01
helm-yas-display-key-on-candidate t
helm-quick-update t
helm-M-x-requires-pattern nil)
(helm-mode)
)
:bind (
("C-h a" . helm-apropos)
("C-x C-b" . helm-buffers-list)
("C-x b" . helm-buffers-list)
("M-y" . helm-show-kill-ring)
("M-x" . helm-M-x)
("C-x C-f" . helm-find-files)
("C-c h o" . helm-occur)
("C-c h r" . helm-register)
("C-c h b" . helm-resume)
)
:config
(setq helm-command-prefix-key "C-c h")
(setq helm-autoresize-min-height 25)
(setq helm-autoresize-max-height 25)
(setq helm-split-window-in-side-p t
helm-move-to-line-cycle-in-source t
helm-ff-search-library-in-sexp t
helm-scroll-amount 8
helm-ff-file-name-history-use-recentf t)
(setq helm-buffer-max-length nil)
(helm-mode 1)
(helm-autoresize-mode 1)
(define-key helm-map (kbd "<tab>") 'helm-execute-persistent-action)
(define-key helm-map (kbd "C-i") 'helm-execute-persistent-action)
(define-key helm-map (kbd "C-z") 'helm-select-action)
:ensure helm)
(use-package helm-swoop
:ensure t
:bind (("C-c h s" . helm-multi-swoop))
:init
(bind-key "M-i" 'helm-swoop-from-isearch isearch-mode-map)
:config
(define-key helm-swoop-map (kbd "M-i") 'helm-multi-swoop-current-mode-from-helm-swoop)
)
In myriad online examples I have seen the mode map bindings of helm-swoop both configured in the config: section, I can't seem to put the helm-swoop-map one in init: because I get a void symbol name error, but I have to put the isearch-mode-map binding in init otherwise the binding does not get set on startup. Why could this be?
Here's a minimal snippet to get things going:
(define-prefix-command 'foo)
(define-key foo "a" 'bar)
(define-key foo "b" 'baz)
(global-set-key (kbd "C-M-r") 'foo)
Now I can "call" the foo keymap when I press C-M-r.
But I wonder how I can do this from code, e.g. something like:
(funcall (lambda-from-keymap 'foo))
After this call, I expect the focus to be in the minibuffer, expecting either
a, or b or C-h to be entered.
Is something like this possible?
You can use read-key-sequence and lookup-key to implement this:
(defun call-keymap (map &optional prompt)
"Read a key sequence and call the command it's bound to in MAP."
;; Note: MAP must be a symbol so we can trick `describe-bindings' into giving
;; us a nice help text.
(let* ((overriding-local-map `(keymap (,map . ,map)))
(help-form `(describe-bindings ,(vector map)))
(key (read-key-sequence prompt))
(cmd (lookup-key map key t)))
(if (functionp cmd) (call-interactively cmd)
(user-error "%s is undefined" key))))
If you hit C-h read-key-sequence still waits for you to complete the sequence. I think you could simulate Emacs' normal behaviour by looping with read-key instead, it's a bit more involved though.
Use it like this:
(defun bar () (interactive) (message "you called bar"))
(defun baz () (interactive) (message "you called baz"))
(define-prefix-command 'foo)
(define-key foo "a" 'bar)
(define-key foo "b" 'baz)
(global-set-key (kbd "C-M-r") 'foo)
(defun call-foo ()
(interactive)
;; Note: pass the symbol form of the keymap so we can give nice help
(call-keymap 'foo "enter a foo command: "))
(global-set-key (kbd "C-c f") 'call-foo)
If the keymap is bound to a key sequence, you can invoke it by emulating the exact key sequence by setting unread-command-events:
(setq unread-command-events
(mapcar (lambda (e) `(t . ,e))
(listify-key-sequence (kbd "C-M-r"))
You need to have foo interactive. I did so using:
(global-set-key (kbd "C-M-r") (lambda () (interactive) ( foo)))
This should fix your problem.
I suppose my problem is pretty obvious, but I don't know Lisp and can't figure it out. Every time I try to write a capital "M" in a python file it won't work (It seems to think that's a start of a shortcut). My guess is that's somewhere in a module or my .emacs file it tries to bind something to Alt + something. But instead it binds it to capital M something. Here's my .emacs file (of which I copied most of it from the net):
; load-path setting is only needed if the directory you put
; weblogger.el in isn't already in your load-path
(add-to-list 'load-path "~/.emacs.d/")
; Remap Ctrl-tab to M-Tab
(define-key function-key-map [(control tab)] [?\M-\t])
(require 'ipython)
(define-key py-mode-map (kbd "M-") 'anything-ipython-complete)
(define-key py-shell-map (kbd "M-") 'anything-ipython-complete)
(define-key py-mode-map (kbd "C-c M") 'anything-ipython-import-modules-from-buffer)
(require 'python-mode)
(add-to-list 'auto-mode-alist '("\\.py\\'" . python-mode))
(require 'python-pep8)
(require 'python-pylint)
(require 'lambda-mode)
(add-hook 'python-mode-hook #'lambda-mode 1)
(require 'comint)
(define-key comint-mode-map (kbd "M-") 'comint-next-input)
(define-key comint-mode-map (kbd "M-") 'comint-previous-input)
(define-key comint-mode-map [down] 'comint-next-matching-input-from-input)
(define-key comint-mode-map [up] 'comint-previous-matching-input-from-input)
(autoload 'pylookup-lookup "pylookup")
(autoload 'pylookup-update "pylookup")
(setq pylookup-program "~/.emacs.d/pylookup/pylookup.py")
(setq pylookup-db-file "~/.emacs.d/pylookup/pylookup.db")
(global-set-key "\C-ch" 'pylookup-lookup)
(autoload 'autopair-global-mode "autopair" nil t)
(autopair-global-mode)
(add-hook 'lisp-mode-hook
#'(lambda () (setq autopair-dont-activate t)))
(add-hook 'python-mode-hook
#'(lambda ()
(push '(?' . ?')
(getf autopair-extra-pairs :code))
(setq autopair-handle-action-fns
(list #'autopair-default-handle-action
#'autopair-python-triple-quote-action))))
(require 'python-pep8)
(require 'python-pylint)
(add-hook 'before-save-hook 'delete-trailing-whitespace)
(autoload 'pylookup-lookup "pylookup")
(autoload 'pylookup-update "pylookup")
(setq pylookup-program "~/.emacs.d/pylookup/pylookup.py")
(setq pylookup-db-file "~/.emacs.d/pylookup/pylookup.db")
(global-set-key "\C-ch" 'pylookup-lookup)
;; Initialize Rope
(pymacs-load "ropemacs" "rope-")
(setq ropemacs-enable-autoimport t)
(require 'auto-complete)
(global-auto-complete-mode t)
;(when (require 'auto-complete nil t)
; (require 'auto-complete-yasnippet)
; (require 'auto-complete-python)
; (require 'auto-complete-css)
; (require 'auto-complete-cpp)
; (require 'auto-complete-emacs-lisp)
; (require 'auto-complete-semantic)
; (require 'auto-complete-gtags))
; (global-auto-complete-mode t)
; (setq ac-auto-start 3)
; (setq ac-dwim t)
; (set-default 'ac-sources '(ac-source-yasnippet ac-source-abbrev ac-source-words-in-buffer ac-source-files-in-current-dir ac-source-symbols))
; (load-library "init_python")
Any idea where I should start looking for the problem? A simple search or any other way to debug the files in the .emacs-directory?
This looks wrong to me:
(define-key py-mode-map (kbd "M-") 'anything-ipython-complete)
(define-key py-shell-map (kbd "M-") 'anything-ipython-complete)
(define-key comint-mode-map (kbd "M-") 'comint-next-input)
(define-key comint-mode-map (kbd "M-") 'comint-previous-input)
kbd expect a full binding, but you're trying to bind M-
to some functions. I suspect a letter is missing.
i.e.
(define-key py-mode-map (kbd "M-TAB") 'anything-ipython-complete)
Here, M stands for META which is usually bound to ALT
or ESC.
By the way, you can do XC-h to see
minor mode bindings starting with X.
I am trying to use One-Key Macros (as was written here)
(defun toggle-kbd-macro-recording-on ()
"One-key keyboard macros: turn recording on."
(interactive)
(define-key
global-map
(events-to-keys (this-command-keys) t)
'toggle-kbd-macro-recording-off)
(start-kbd-macro nil))
(defun toggle-kbd-macro-recording-off ()
"One-key keyboard macros: turn recording off."
(interactive)
(define-key
global-map
(events-to-keys (this-command-keys) t)
'toggle-kbd-macro-recording-on)
(end-kbd-macro))
(global-set-key '[(f1)] 'call-last-kbd-macro)
(global-set-key '[(shift f1)] 'toggle-kbd-macro-recording-on)
But when I press Shift-F1 I get error:
define-key: Symbol's function
definition is void: events-to-keys
How can I fix it?
The events-to-keys function seems to be something obsolete. From what I can tell, it should work by just writing:
(defun toggle-kbd-macro-recording-on ()
"One-key keyboard macros: turn recording on."
(interactive)
(define-key
global-map
(this-command-keys)
'toggle-kbd-macro-recording-off)
(start-kbd-macro nil))
(defun toggle-kbd-macro-recording-off ()
"One-key keyboard macros: turn recording off."
(interactive)
(define-key
global-map
(this-command-keys)
'toggle-kbd-macro-recording-on)
(end-kbd-macro))
(global-set-key '[(f1)] 'call-last-kbd-macro)
(global-set-key '[(shift f1)] 'toggle-kbd-macro-recording-on)