I wrote an elisp macro that preserves the region when in transient-mark-mode:
(defmacro keep-region (command)
"Wrap command in code that saves and restores the region"
(letrec ((command-name (symbol-name command))
(advice-name (concat command-name "-keep-region")))
`(progn
(defadvice ,command (around ,(intern advice-name))
(let (deactivate-mark)
(save-excursion
ad-do-it)))
(ad-activate (quote ,command)))))
(keep-region replace-string)
(keep-region replace-regexp)
This preserves the region for commands that are advised using the keep-region macro; very helpful when you want to make multiple replacements in a selected block.
The problem is that after running a command that has been advised using this macro, the region loses its transient nature; subsequent movement commands extend the region, rather than deselecting it.
How can I programmatically re-enable the transience of the marked region?
From C-h f transient-mark-mode:
Transient Mark mode is a global minor mode. When enabled, the
region is highlighted whenever the mark is active. The mark is
"deactivated" by changing the buffer, and after certain other
operations that set the mark but whose main purpose is something
else--for example, incremental search, <, and >.
Hence, activate-mark after exchange-point-and-mark should restore the transient nature of the mark.
I am not sure, though, why you are using exchange-point-and-mark here, and why you are calling it twice. In my opinion, just saving (point) and (mark) in a let-binding and restoring them after ad-do-it would be easier. push-mark and pop-mark might help as well, since the latter automatically reactivates the mark anyway.
The problem is that after running a command that has been advised using this macro, the region loses its transient nature; subsequent movement commands extend the region, rather than deselecting it.
You should rather talk about "shift-selected nature": movement commands extending the region is what happens when the mark is activated in the "normal" way.
The shift-select status is stored inside the transient-mark-mode variable, and is modified by someone (handle-shift-selection?) who doesn't care about the value of deactivate-mark. We can get around this by saving the value of transient-mark-mode:
(defmacro keep-region (command)
"Wrap command in code that saves and restores the region"
(letrec ((command-name (symbol-name command))
(advice-name (concat command-name "-keep-region")))
`(progn
(defadvice ,command (around ,(intern advice-name))
(let ((deactivate-mark nil)
(transient-mark-mode transient-mark-mode))
(save-excursion
ad-do-it)))
(ad-activate (quote ,command)))))
transient-mark-mode is a variable defined in `buffer.c'.
...
Lisp programs may give this variable certain special values:
...
A value of (only . OLDVAL) enables Transient Mark mode temporarily. After any subsequent point motion command that is not
shift-translated, or any other action that would normally deactivate
the mark (e.g. buffer modification), the value of
`transient-mark-mode' is set to OLDVAL.
Just remove your calls to exchange-point-and-mark. The preservation is done by the deactive-mark let-binding anyway.
Related
Is there a way to show full command history with arguments?
repeat-complex-command which is bound to:
<again>, <redo>, C-x M-:, C-x M-ESC
does not show commands that are invoked from key bindings, and kmacro-edit-macro (which is bound to C-x C-k RET) does not show arguments passed to commands.
Motivation. It would make it faster to turn a keyboard macro into an elisp function. For now, I invoke kmacro-edit-macro to see names of commands to use and then work out what arguments to pass by reading documentation of commands one by one. (Example workflow: https://stackoverflow.com/a/24784563/1446335)
Note. It is possible to programmatically press key sequence from within an elisp function, but its usefulness is small.
Yes, to get what you want, use pre-command-hook to invoke a function that adds the given command to extended-command-history. For example, this is what the Icicles code does to add commands executed by menu to this history:
;; This is done when you turn on Icicle mode.
(if icicle-menu-items-to-history-flag
(add-hook 'pre-command-hook 'icicle-add-menu-item-to-cmd-history)
(remove-hook 'pre-command-hook 'icicle-add-menu-item-to-cmd-history))
(defun icicle-add-menu-item-to-cmd-history ()
"Add `this-command' to command history, if it is a menu item.
Menu items that are not associated with a command symbol are ignored.
Used on `pre-command-hook'."
(condition-case nil ; Just in case, since this is on `pre-command-hook'.
(when (and (> (length (this-command-keys-vector)) 0)
(equal '(menu-bar) (elt (this-command-keys-vector) 0))
;; Exclude uninterned symbols such as `menu-function-356'.
(symbolp this-command) (or (< emacs-major-version 21) (intern-soft this-command)))
(pushnew (symbol-name this-command) extended-command-history))
(error nil)))
It would be great to have a way to turn a keyboard-macro into a chunk of Elisp code, but for this chunk of Elisp code to be useful, it should be somewhat idiomatic, yet in many cases, the idiomatic Elisp code to do something is quite different from the keyboard-macro way to do it (e.g. idiomatic code should not use the mark and the kill ring just to extract and move text around).
So the transcription is not straightforward. I think the way to write such a thing is to "start small" and accept the fact that it will not be 100% reliable.
After doing a (re-search-forward str) in the current buffer, it would be nice in some cases to have an easy method to return to the previous buffer position. The behavior should be like (undo) for buffer changes. So if I do two searches forward, first from position A to B, and then from B to C, I would like to press a key to go back one step (from C to B), and pressing the key again would leave me at A..
If you are using re-search-forward in Lisp code (and you probably should be, if you are using it at all, even though it is a command), then do not set the mark in order to be able to return to your starting point.
Instead, simply save the starting position ((point)) as, say, variable beg, and then use goto-char beg.
See this paragraph in (elisp) The Mark:
Novice Emacs Lisp programmers often try to use the mark for the
wrong purposes. The mark saves a location for the user's
convenience. An editing command should not alter the mark unless
altering the mark is part of the user-level functionality of the
command. (And, in that case, this effect should be documented.)
To remember a location for internal use in the Lisp program, store
it in a Lisp variable. For example:
(let ((beg (point)))
(forward-line 1)
(delete-region beg (point))).
With this
(global-set-key
(kbd "M-p")
(lambda()(interactive) (set-mark-command 4)))
I can jump backwards one by one through a few C-M-s.
Note that this works for isearch-forward-regexp, not for plain
re-search-forward (this one doesn't set the mark).
But with elisp it's no problem - just call push-mark before
re-search-forward.
To sum up, the following seems to work:
(defun my-search-fun (str)
(interactive)
(push-mark)
(beginning-of-buffer)
(re-search-forward str))
(defun my-undo-search ()
(interactive)
(pop-mark)
(goto-char (mark))
This question is related to another one, Emacs :TODO indicator at left side. I recently came across a minor mode I like a lot called FixmeMode. It supports auto highlighting of TODO marks, and navigating between them. However, I think it makes more sense to recognize the "TODO" strings only in comments, rather than polluting the whole file. Is it possible?
Check out the library fic-mode.el, it has been verified in C++ and Emacs-Lisp.
It was written specifically to answer this question.
The installation is like any standard package:
(require 'fic-mode)
(add-hook 'c++-mode-hook 'turn-on-fic-mode)
Though Wei Hu did ask for an easy way to add it to multiple modes, so here goes:
(defun add-something-to-mode-hooks (mode-list something)
"helper function to add a callback to multiple hooks"
(dolist (mode mode-list)
(add-hook (intern (concat (symbol-name mode) "-mode-hook")) something)))
(add-something-to-mode-hooks '(c++ tcl emacs-lisp) 'turn-on-fic-mode)
It's possible but quite a bit trickier. Fixme mode uses font-lock to do its highlighting, so it works on an as-you-type basis to highlight the keywords. Font-lock hooks in at a very low level, basically running after every change is made to the buffer's contents. It is highly optimized, though, which allows it to appear instantaneous on modern computers.
The TODO indicator in the left fringe is static. Execute the function and all current TODO's are highlighted; change the buffer (adding or removing TODO's) does not change the fringe indicator; that's only changed when the function runs again.
Your approach would have to get into syntax tables, determining first when you're in a comment and then looking for the keywords. The tricky part comes in doing this interactively (i.e. as you type). You should be able to hook into the font-lock constructs to do this, but the function you provide to search for the comment syntax table and then for the keywords better be very efficient, as it will be run each and every time a buffer changes (though it will only run on the changed region, I think). You would want to stuff all of this in font-lock-syntactic-keywords rather than font-lock-keywords because the syntactic-keyword pass happens before the syntactic pass (which happens before the keyword pass), and you need to set TODO inside comments before comments themselves are set.
Sorry it's not a full working-code answer.....
Maybe this will help: there's a fn c-in-literal in
cc-mode, and a similar csharp-in-literal in csharp mode. The
return value is c if in a C-style comment, c++ if in a C++
style comment. You could add that to the code at
Emacs :TODO indicator at left side
to get what you want.
(defun annotate-todo ()
"put fringe marker on TODO: lines in the curent buffer"
(interactive)
(let (lit)
(save-excursion
(goto-char (point-min))
(while (re-search-forward "TODO:" nil t)
(progn
(setq lit (c-in-literal)) ;; or csharp-in-literal
(if (or (eq lit 'c) (eq lit 'c++))
(let ((overlay (make-overlay (- (point) 5) (point))))
(overlay-put overlay 'before-string
(propertize "A"
'display
'(left-fringe ;; right
horizontal-bar
better-fringes-important-bitmap))))))))))
https://github.com/tarsius/hl-todo seems to do exactly what you want. I just tried it and love it.
I have a minor mode. If that mode is active and the user hits DEL, I
want to do some action, but only if some condition holds. If the
condition holds and the action is executed I want to do nothing more
after that. But if the condition fails, I don't want to do anything
and let the default DEL action execute.
Not sure how I could solve this. But I guess I could do it in two ways:
1)
I could rebind the DEL key to a function in the minor mode and then
check if the conditions holds ot not. But then how do I know what the
default command to DEL is?
2)
I could add a pre command hook like this. Execute the command and then
break the chain. But how do I break the chain?
(add-hook 'pre-command-hook
(lambda()
(when (equal last-input-event 'backspace)
;; Do something and then stop (do not execute the
;; command that backspace is bound to)
)))
In what way would you solve it? Thanks!
The way to do this is to temporarily disable your minor mode, then look up the key binding.
Pretend that you've bound 'do-thingy to DEL. Then this would do the trick (assuming the condition you want to trigger off is (equal last-input-event 'backspace):
(defun do-thingy ()
"Do something, unless last event was backspace."
(interactive)
(if (equal last-input-event 'backspace)
(let* ((my-minor-mode nil)
(original-func (key-binding (kbd "DEL"))))
;; original-func is whatever DEL would be if
;; my-minor-mode were disabled
(call-interactively original-func))
(message "Here's my minor mode behavior!")))
Note: This behavior assumes you have set up your key bindings the standard way a minor-mode would. Specifically, you should add your keymap to the variable minor-mode-map-alist by adding an element (my-minor-mode . my-minor-mode-keymap). That's how the above let statement works, it looks up the binding you want with your mode temporarily disabled.
If you use define-minor-mode to define your minor mode, the keymap gets set up the "right way" automatically.
This is what I use for my smart-tab package which does exactly that.
(defun smart-tab-default ()
"Indents region if mark is active, or current line otherwise."
(interactive)
(if mark-active
(indent-region (region-beginning)
(region-end))
(call-interactively
(or
;; Minor mode maps for tab (without smart-tab-mode)
(cdar (assq-delete-all 'smart-tab-mode (minor-mode-key-binding "\t")))
(cdar (assq-delete-all 'smart-tab-mode (minor-mode-key-binding [(tab)])))
(local-key-binding "\t")
(local-key-binding [(tab)])
(global-key-binding "\t")
(global-key-binding [(tab)])))))
And in the command smart-tab (which is the one bound to tab in the minor
mode), it has the following:
(if (smart-tab-must-expand prefix)
;; use smart tab
(smart-tab-default))
It first checks if there are any minor mode bindings for tab (not including
smart-tab-mode), then local, and finally global keybindings.
There doesn't seem to be a way to do what you want reliably. If your new command is bound to DEL, then whatever was bound to DEL before in the current keymap isn't there anymore. The other approach you proposed won't work because pre-command-hooks don't prevent the following action from taking place. You might also think to interrupt further execution with ^G (Keyboard-Quit), but that's an uncontrolled interrupt that might stop more things than you want.
Even if you make the process of setting up the new binding a little more sophisticated than just re-bind, and remember what was bound there before, so you can call it afterwards, you don't really have what your looking for. If someone wants to rebind the "default" action, they have to do it by modifying to your function rather than replacing the key binding.
What you want to do doesn't fit Emacs' model of how key binding works.
How do you list the active minor modes in emacs?
C-h m or M-x describe-mode shows all the active minor modes (and major mode) and a brief description of each.
A list of all the minor mode commands is stored in the variable minor-mode-list. Finding out whether they're active or not is usually done by checking the variable of the same name. So you can do something like this:
(defun which-active-modes ()
"Give a message of which minor modes are enabled in the current buffer."
(interactive)
(let ((active-modes))
(mapc (lambda (mode) (condition-case nil
(if (and (symbolp mode) (symbol-value mode))
(add-to-list 'active-modes mode))
(error nil) ))
minor-mode-list)
(message "Active modes are %s" active-modes)))
Note: this only works for the current buffer (because the minor modes might be only enabled in certain buffers).
describe-mode can somehow come up with a list of enabled minor modes, why couldn't I? So after reading its source code I realized that it gets the list of active minor modes from both minor-mode-list and minor-mode-alist. Using 3rd-party dash.el list manipulation library I came with this code:
(--filter (and (boundp it) (symbol-value it)) minor-mode-list)
So, for example, to disable all minor modes, use -each:
(--each (--filter (and (boundp it) (symbol-value it)) minor-mode-list)
(funcall it -1))
Don't forget to save the list of minor modes in a variable, otherwise you would have to restart Emacs or enable them by memory.
If you want to programmatically do something with all buffers that have a certain mode active, then the best, most minimalistic, cleanest, built-in solution is as follows:
(dolist ($buf (buffer-list (current-buffer)))
(with-current-buffer $buf
(when some-buffer-local-minor-or-major-mode-variable-you-want-to-find
(message "x %s" $buf))))
It does the following:
Retrieve a list of all buffers via buffer-list, with the currently active buffer at the head of the list (so it's treated first, usually what you want, but leave out the current-buffer parameter if you don't care).
Loop through the buffer list and assign each buffer name to the variable $buf.
Use with-current-buffer $buf to tell Emacs that all code within the body should run as if it was running inside buffer $buf instead of whatever buffer you're really displaying on screen.
when <some mode variable> is the correct way to check if a mode is enabled; you can also use if and other such methods. Either way, the goal is to check if a minor or major-mode's main mode variable is set in the buffer. Almost all modes define a variable via "defining" a mode, which automatically causes them to create a buffer-local variable named after the mode, which is how this works. And if they don't have a standard variable, look at their own source code to see how their "toggle" code determines how to toggle them on and off. 99% of them use the existence of their modename's variable (and if they don't, I suggest reporting that as a bug to the mode's author). For example, to check if a buffer has whitespace-mode active, you would say when whitespace-mode.
After that, it just outputs a message to the Messages buffer, with an "x" and the name of the buffer that had the mode active. That's where you'd put your own code, to do whatever you wanted to do with the discovered buffer.
Enjoy! Onwards to greater and cleaner lisp code!
Here is a simple alternative snippet similar to some of the methods that have already been addressed in other answers:
(delq nil
(mapcar
(lambda (x)
(let ((car-x (car x)))
(when (and (symbolp car-x) (symbol-value car-x))
x)))
minor-mode-alist))
If you just want to know if a particular minor mode (say, evil-mode) is active in the buffer, you could evaluate the following:
(when (member 'evil-mode minor-mode-list)
(message "`evil-mode' is active!"))