emacs - set shortcut key only in major mode? - emacs

I would like to override C-l and use it to do M-x erase-buffer followed by simulating hitting RET, only when I am in m-shell-mode. C-l should be its default, recenter-top-bottom, otherwise. How do I do so?

Not sure what m-shell-mode is, but if it's a well-defined major mode, then the following should do the trick:
(require 'm-shell-mode)
(define-key m-shell-mode-map (kbd "C-l") 'erase-buffer)
Might I suggest an alternative binding, which has the same visual effect, but keeps the buffer contents around (which can be handy).
(defun shell-clear-command (&optional a)
"\"clear\" the screen"
(interactive "P")
(recenter (or a 0)))
(define-key m-shell-mode-map (kbd "C-l") 'shell-clear-command)

If m-shell-mode is based on comint-mode, which is true of many modes that provide a shell to interact with another process, then you can pass the return keypress to matlab with the function comint-send-input. In that case the following code should do what you want:
(defun clear-and-return ()
"Erases the buffer, and then passes a return to the buffer process.
Assumes the buffer is attached to a comint process."
(interactive)
(erase-buffer)
(comint-send-input))
(defun my-m-shell-mode-hook ()
(local-set-key (kbd "C-l") 'clear-and-return))
(add-hook 'm-shell-mode-hook 'my-m-shell-mode-hook)
The first defun makes a function that does what you want. The second is a hook function that will bind C-l to that function for the buffer that is active when the function is called. The add-hook tells emacs to run the second function whenever you start m-shell-mode. You can add further m-shell-mode customizations inside the body of my-m-shell-mode, and Emacs will run all of them each time you start the mode.
If m-shell-mode is not based on comint-mode, you need to find out what happens when you press return. From a buffer that is running the mode, type C-h k RET to find the function bound to the return key. Use that function instead of comint-send-input in the code above.

You can add to your m-shell-mode hook the following code:
(local-set-key (kbd "C-l") 'erase-buffer)

Related

Control Emacs behavior when splitting windows

I would like to customize the behavior when I split windows in Emacs:
I am always splitting because I want to view a separate buffer side-by-side with the one I'm currently editing.
I use electric-buffer-list (bound to C-x C-b) to navigate buffers.
I end up doing all of the following separately:
C-x 3 to split horizontally.
C-x o to switch to the other window.
C-x C-b to invoke electric-buffer-list so I can select the buffer I want to view.
It seems like I should be able to write an Elisp function that will do all of this when I press C-x 3.
I found this post which describes the focus switching part of the behavior that I want, but I don't understand how to extend that answer to achieve all of what I'm trying to do.
Edit: After reviewing #lawlist's post and debugging my syntax, I think I want to do something like this:
(defun split-right-and-buffer-list ()
(interactive)
(split-window-horizontally)
(other-window 0)
(electric-buffer-list 0))
(global-set-key (kbd "C-x 3") 'split-right-and-buffer-list)
This does everything I want, except that the buffer list that comes up only lists the current buffer, instead of the normal list of all buffers that I get when I invoke electric-buffer-list from its key binding.
With some very small modifications the function you came up with will do what you want:
(defun split-right-and-buffer-list ()
(interactive)
(split-window-horizontally)
(other-window 1)
(electric-buffer-list nil))
(global-set-key (kbd "C-x 3") 'split-right-and-buffer-list)
Passing 1 instead of 0 as an argument to other-window causes Emacs to select the new window created as a result of calling split-window-horizontally.
Passing nil instead of 0 as an argument to electric-buffer-list causes Emacs to show all buffers, not just file-visiting ones.
The thing that can trip you up here is that this isn't mentioned in the documentation for electric-buffer-list (which doesn't include any information about the ARG it takes). But when you look at the source code of this command, you'll notice that it simply passes the value of the argument on to a function called list-buffers-noselect (and doesn't use it for anything else). The documentation of this function contains the missing piece of information mentioned above.
If you do not mind having custom commands to do what you want try the following functions
(require 'ido)
(defun my-split-window-open-buffer-right (buffer)
(interactive (list (ido-read-buffer "Please select a buffer: ")))
(select-window (split-window-right))
(switch-to-buffer buffer))
(defun my-split-window-open-buffer-below (buffer)
(interactive (list (ido-read-buffer "Please select a buffer: ")))
(select-window (split-window-below))
(switch-to-buffer buffer))
Bind them to keys of you liking. I would prefer this over redefining/advising functions I have not written.

how to emulate a specific key press in Emacs Lisp

Context: I want to make a minor mode where pressing f twice fast results in whatever the pressing of ( should do at that time. This doesn't always mean just insertion of (. For example, in buffers where paredit mode or autopair mode is enabled, pressing of ( usually results in insertion of (). In a paredit mode buffer, that sometimes results in wrapping the selected text: for example, if I select a b and press (, that should result in replacing the selection with (a b).
For detection of f being pressed twice, I just need to take the logic in the short code in http://www.emacswiki.org/emacs/electric-dot-and-dash.el
So the only missing piece is a Lisp code snippet that tells Emacs "Trigger pressing of ( now!"
The first thing that came to my mind was that the snippet should do
find the command bound to the key (
and then call call-interactively on that command.
but that breaks down if the auto pairing package (autopair or paredit or other similar package) binds ( to a command that has a logic that looks up what key was used to call the command, or if the package simply relies on post-self-insert-hook or post-command-hook instead of binding (.
update
I've looked up Key Chord documentation and it turns out what I am trying to do with answers to this question has a simpler solution:
(require 'key-chord)
(key-chord-mode 1)
(defvar my-easy-open-paren-mode-map
(let ((map (make-sparse-keymap)))
(key-chord-define map ",." (kbd "("))
map))
(define-minor-mode my-easy-open-paren-mode
"In this mode, pressing . and , together is another way of pressing the open paren.")
(defvar my-easy-semicolon-mode-map
(let ((map (make-sparse-keymap)))
(key-chord-define map ";;" (kbd "C-e ;"))
map))
(define-minor-mode my-easy-semicolon-mode
"In this mode, pressing semicolon twice fast is another way of pressing C-e and semicolon.")
(add-hook 'prog-mode-hook 'my-easy-open-paren-mode)
(add-hook 'c-mode-common-hook 'my-easy-semicolon-mode)
Triggering key press may still be useful in other contexts though.
You might appreciate the Key Chord library for binding functions to a double key-press. (I wouldn't recommend using f if you'll be writing in English, mind you; but YMMV.)
post-self-insert-hook would still run if the binding was self-insert-command. post-command-hook will run in any case, but if you're worried about it seeing an incorrect function and/or input event, you can manipulate those...
After looking up the binding, your function can set this-command to the function you're about to call-interactively, and last-command-event to the required key. e.g.:
(defun my-fake-paren ()
(interactive)
(let ((command (key-binding "(")))
(setq last-command-event ?\()
(setq this-command command)
(call-interactively command)))
I use Key Chord for this sort of thing, although the page you link appears to do the same thing. The trick is getting the call to call-interactively to work correctly. I wrapped it in a let that reset the variable last-command-event, such that call-interactively thinks it was a "(". This works for me in paredit and fundamental modes.
(require 'key-chord)
(key-chord-mode 1)
(defun my-paren-call ()
(interactive)
(let ((last-command-event ?\())
(call-interactively (key-binding "("))))
(key-chord-define-global "ff" 'my-paren-call)

Emacs can't reset Ctrl-d key behaviour

I wanted to change the behaviour of Ctrl-d key. So it will delete a word backward. I created a function:
(defun backward-delete-word (arg)
"Delete characters backward until encountering the beginning of a word.
With argument ARG, do this that many times."
(interactive "p")
(delete-region (point) (progn (backward-word arg) (point))))
Then inserted this into emacs.d:
(global-set-key (kbd "\C-d") 'backward-delete-word)
It works in fundamental-mode, but in php-mode it just removes the next character. When I click
Ctrl-h k Ctrl-d
Emacs gives this:
C-d runs the command c-electric-delete-forward, which is an
interactive compiled Lisp function in `cc-cmds.el'.
It is bound to C-d.
(c-electric-delete-forward ARG)
Somehow, it was reset to another function. How to find out, where it was reset and make it work with my function instead?
I don't have php-mode so I can't say for sure, but the binding is likely overriden in php-mode-map (which, as a major mode map, has higher precedence than the global map).
You can check by using C-h b to list all available key bindings and look for C-d or c-electric-delete-forward in the output buffer to see in which keymap the binding is defined.
Assuming php-mode-map overrides the C-d binding, you can disable it using
(define-key php-mode-map (kbd "C-d") nil)

Set custom keybinding for specific Emacs mode

Though I know how to set a global key-binding in Emacs, I find it hard to even Google out the code for a local (minor-mode specific) key-binding. For instance, I have this code in my .emacs:
;; PDFLaTeX from AucTeX
(global-set-key (kbd "C-c M-p")
(lambda ()
(interactive)
(shell-command (concat "pdflatex " buffer-file-name))))
I don't want to set it globally. Is there a function like local-set-key?
I use the following:
(add-hook 'LaTeX-mode-hook
(lambda () (local-set-key (kbd "C-0") #'run-latexmk)))
to have a bind defined for LaTeX mode alone.
To bind a key in a mode, you need to wait for the mode to be loaded before defining the key. One could require the mode, or use eval-after-load
(eval-after-load 'latex
'(define-key LaTeX-mode-map [(tab)] 'outline-cycle))
Don't forget either '—eval-after-load is not a macro, so it needs them.
You need to identify the key map for that mode (for example, LaTeX-mode-map) and use the function define-key. As an example, along with activating outline-minor-mode within LaTeX mode, I have:
(define-key LaTeX-mode-map [(tab)] 'outline-cycle))
In this case the major mode (LaTeX) holds the key binding, but there is also an outline-minor-mode-map.
None of the other answers satisfied my needs. So this may help other people. I wanted Tab to jump to the beginning of the line if I'm in Evil's normal mode (basically this means everywhere in Emacs), but I instead wanted it to cycle between org item states if I am in an org-mode document.
One option was to mess around with separate bindings and constant binding-rebinding whenever I switched buffers (because evil allows only one binding per key in its normal state).
But a more efficient option was to make Tab run my own code which runs the required function based on which major mode the current buffer uses. So if I am in a org buffer, this code runs org-cycle, and otherwise it runs evil-first-non-blank (go to the first non-whitespace character on the line).
The technique I used here can also be used by calling your custom function via global-set-key instead, for people who use regular non-evil Emacs.
For those who don't know Emacs lisp, the first line after the "if" statement is the true-action, and the line after that is the false-action. So if major-mode equals org-mode, we run org-cycle, otherwise we run evil-first-non-blank in all other modes:
(defun my/tab-jump-or-org-cycle ()
"jumps to beginning of line in all modes except org mode, where it cycles"
(interactive)
(if (equal major-mode 'org-mode)
(org-cycle)
(evil-first-non-blank))
)
(define-key evil-normal-state-map (kbd "<tab>") 'my/tab-jump-or-org-cycle)

In Emacs, can we make one keystroke to do different command?

I want to make one keystroke, say C-F12, to do delete-other-windows or winner-undo. I think it's easy if I already learning Emacs Lisp programming, and set a boolean flag. That is, if previously it run delete-other-window, now it'll run winner-undo.
How do you do that in Emacs Lisp?
Thanks
Try something like this
(setq c-f12-winner-undo t)
(define-key (current-global-map) [C-f12]
(lambda()
(interactive)
(if c-f12-winner-undo
(winner-undo)
(delete-other-windows))
(setq c-f12-winner-undo (not c-f12-winner-undo))))
(defun swdev-toggle-sole-window ()
(interactive)
(if (cdr (window-list))
(delete-other-windows)
(winner-undo)))
(global-set-key (kbd "<C-f12>") 'swdev-toggle-sole-window)
The first line starts the declaration of a function called swdev-toggle-sole-window, taking no argument.
This function is declared as interactive, i.e. it can be called with M-x or through a key binding.
If the window list contains more than one element, i.e. if there is more than one window, …
… then delete other windows …
… else undo the window deletion.
Bind the function to the key C-f12.
Here's a solution using the approach taken by Emacs' recenter-top-bottom function:
(defun delete-other-window-or-winner-undo ()
"call delete-other-window on first invocation and winner-undo on subsequent invocations"
(interactive)
(if (eq this-command last-command)
(winner-undo)
(delete-other-windows)))
(global-set-key (kbd "<C-f12>") 'delete-other-window-or-winner-undo)