Undo buffer-search in Emacs - emacs

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))

Related

emacs call-interactively and key simulation

I want to write a small function that saves the cursor's current position, mark the whole buffer, indents it and then goes back to the previous cursor position. I understand there might be easier way to achieve the same result but I'd like to understand how these principles work in Elisp.
Here's what I tried to do :
(defun indent-whole-buffer () (interactive)
(call-interactively 'point-to-register)
(call-interactively (kbd "RET"))
(mark-whole-buffer)
(call-interactively 'indent-region)
(call-interactively 'jump-to-register)
(call-interactively (kbd "RET"))
)
The blocking point here is the (call-interactively (kbd "RET")) how can I simulate the RET key, just as if I was doing
M-x point-to-register RET
Just use save-excursion. That's what it's for. It saves point and mark and which buffer is current, and then restores them for you.
(And if you did decide to roll your own, and you did decide to do it in the way you planned, then just call the functions you need directly - no need to use call-interactively. Use C-h f to see how each function is called. For example (point-to-register ?a) captures point in register a, and (indent-region (point-min) (point-max)) indents the whole buffer.)
Emacs Lisp is not just the macro language used by Emacs — it's the implementation language. Many Emacs functions have more functionality than what is exposed through the UI, and it is often possible to write more compact and elegant code by using this functionality.
In particular, if your goal is to indent the whole buffer, then there is no need to move point and mark around — the function indent-region is able to indent an arbitrary region:
(defun indent-whole-buffer ()
(interactive)
(indent-region (point-min) (point-max)))

Emacs: Assign a function to a keybinding, and with repeated presses, undo the last press and redo at a wider setting

Here's the bigger picture of what I'm trying to do:
With a keypress, it will insert an opening and closing parenthesis right after/before the innermost closing/opening delimiter (bracket, brace, parenthesis, whatever).
But if it is pressed immediately after, it will undo the last insertions, seek out the next closing delimiter, and put it after that, and so on.
I have a working version of the first part, but am looking for "best practices" for the second part (where it undoes and moves outwards)
As a motivator and concrete example, this is a typical scenario when coding in Python. I work with list comprehensions a lot, and often I construct the list, and then decide I want to sum all elements, etc. So I would first type:
[x*x for x in some_lst if is_prime(x)]
and then I'll want to encapsulate this list with a "sum" command:
sum([x*x for x in some_lst if is_prime(x)])
I don't want to have to keep moving the cursor to both the beginning and the end just to insert the parentheses. I'd rather have the point in the list, press a keystroke, have it figure out the delimiters, and place the mark just before the opening inserted parenthesis so that I can type "sum". My function below seems to work (piggybacking on the "expand-region" package):
(defun add-paren ()
(interactive)
(er/mark-outside-pairs)
(exchange-point-and-mark)
(insert-string ")")
(exchange-point-and-mark)
(insert-string "(")
(left-char 1)
)
What's the best practice for the 2nd step?
(Any suggestions/improvements to the above would also be appreciated. This is my first "real" function in Elisp.)
Thanks.
Update: Thanks everyone for the tips. I'll probably use some of them in my final solution. My original question still stands: Is there a standard pattern of "undoing and redoing at a larger scale", or will each problem have its own custom solution? Suppose I use smartparens as suggested to do it all in one keystroke, but I want it to occur on the 3rd level out. What I want is to press the keystroke 3 times and have it place the parentheses there.
So after the first keystroke, it places the parentheses at the innermost level. Pressing it again should remove the inserted parentheses, and place them in the next level up, and so on...
(BTW, not trying to reinvent the wheel. I suspect some of the packages listed may have exactly what I need - I just want practice coding in Elisp).
Update 2:
I guess there is no best practice for this? Anyway, I solved the problem using both expand-region and smartparens:
(defun add-paren ()
(interactive)
(if (eq last-command 'add-paren)
;; (message "AAAA")
(delete-paren)
)
(setq currpoint (point))
(er/mark-outside-pairs)
(if (eq currpoint (point))
(er/mark-outside-pairs)
)
(sp-wrap-with-pair "(")
(left-char 1)
)
(global-set-key (kbd "<f5>") 'add-paren)
(defun delete-paren ()
(interactive)
(setq currloc (point))
(sp-unwrap-sexp)
(goto-char currloc)
(left-char 1)
)
You're already using expand-region. Why not combine that with one of the many "surround region with..." modes?
I personally like smartparens (available via Marmalade or MELPA), but there are many other similar tools.
Use er/expand-region until you've got an appropriate selection, then
( to wrap in parentheses.
When programming, there are several hundred slightly different edit-tasks of this kind. Therefor created a toolkit for it.
In example given, the form might be described as delimited, more precisely bracketed.
ar-bracketed-atpt would mark it.
It's set here like this:
(global-set-key [(super \])] 'ar-bracketed-atpt)
Then comes in another class of commands which do several things on active region. In this case:
M-x ar-parentize-or-copy-atpt RET
It is bound to C-c )
A tarball for all this stuff is available here:
https://launchpad.net/s-x-emacs-werkstatt/
FWIW, I'd do it as follows:
go before the open bracket.
type sum C-M-SPC (
The C-M-SPC selects the parenthesized (well, "bracketized") expression, and the subsequent ( wraps it in parens (because of electric-pair-mode).
I guess there is no best practice for this? Anyway, I solved the problem using both expand-region and smartparens:
(defun add-paren ()
(interactive)
(if (eq last-command 'add-paren)
;; (message "AAAA")
(delete-paren)
)
(setq currpoint (point))
(er/mark-outside-pairs)
(if (eq currpoint (point))
(er/mark-outside-pairs)
)
(sp-wrap-with-pair "(")
(left-char 1)
)
(global-set-key (kbd "<f5>") 'add-paren)
(defun delete-paren ()
(interactive)
(setq currloc (point))
(sp-unwrap-sexp)
(goto-char currloc)
(left-char 1)
)

difference between calling command directly and using keybinding

I'm new to elisp, so please forgive me if the following approach is totally clumsy.
In the team I'm currently working with, there is an usual convention of closing python blocks with a pass statement (if they aren't ended by closing keywords like else or except or such). While unusual, this has the advantage that one can always recover the original indentation of the program if it is unintentionally changed (using emacs indent-region).
To get existing code in line with this convention, I wrote a small elisp function:
(defun python-check-indent ()
"Check if automatic indentation changes current indent, insert pass keyword if it does."
(interactive)
(move-beginning-of-line 1)
(skip-chars-forward " ")
(if
(< 0
(let (original)
(setq original (point))
(indent-for-tab-command)
(- (point) original)
)
)
(progn
(insert "pass")
(newline)
(indent-for-tab-command)
)
)
(next-line)
)
(global-set-key (kbd "C-`") 'python-check-indent)
The idea is simply to test whether hitting TAB would change the indentation, and insert a pass statement in that case. To facilitate processing longer blocks of code, it then advances to the next line.
When I run it using M-x python-check-indent, it does what I want (except that it moves around empty lines slightly), also when running it repeatedly to process several lines. However, when I run it repeatedly using the C-` keybinding, it starts messing up the code from the second invocation on.
So here are my questions: What is the difference between invoking a command with M-x ... and using its keybinding? And how could I change the function to be not affected by this difference?
emacs-version: GNU Emacs 23.3.1 (x86_64-apple-darwin, NS apple-appkit-1038.35) of 2011-03-10 on black.porkrind.org
(edit) current workaround: I'm now wrapping it inside a keyboard-macro, so it's "bound" to C-x e, and behaves properly.
The general rule is that it is best to avoid complex interactive
commands in your functions because they could be affected by all sorts
of options.
(defun python-check-indent ()
"Check if automatic indentation changes current indent, insert pass keyword if it does."
(interactive)
(goto-char (line-beginning-position))
(skip-chars-forward " ")
(when (< 0
(let (original)
(setq original (point))
(python-indent-line)
(- (point) original)))
(insert "pass\n")
(python-indent-line))
(forward-line))
However, even this is probably not good because python-indent-line's behavior depends on last-command and python-indent-trigger-commands. I think it would be best if you replaced the first invocation of python-indent-line with the code which computes the target indentation instead of actually indenting, something like (nth python-indent-current-level python-indent-levels).
PS. If you still have problems, I suggest that you use edebug and step through the function.

Emacs: highlighting TODO *only* in comments

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.

Emacs command to insert and indent line above cursor

I frequently find myself typing on a line, when I realize I need(ed) a variable definition (or something similar) on the line above. What I would like is to
press C-return from anywhere on a line and have the cursor move to a newly inserted blank line above, with correct indentation (or at least the same as the original line).
be able to yank any text...
and C-u C-space to get back to the original position
I've managed to do #1, but my emacs-fu isn't strong enough to do the rest.
Here's my humble solution:
(defun my-insert-before-line ()
(interactive)
(save-excursion
(beginning-of-line)
; I've changed the order of (yank) and (indent-according-to-mode)
; in order to handle the case when yanked line comes with its own indent
(yank)(indent-according-to-mode)
; could be as well changed to simple (newline) it's metter of taste
; and of usage
(newline-and-indent)))
Hope it helps.
Here's what you can do if you are not a Zen master emacs dude.
Emacs has a record-macro thing, kmacro-start-macro and kmacro-end-macro.
After recording your macro, do name-last-kbd-macro. then visit .emacs, and do insert-kbd-macro.
You then have an fset statement that defines your macro. It may look funny, and it is not as maintainable as elisp, but if you stuff it into your .emacs, that macro (by that name) will be available to any of your editing sessions. And you can bind it to a key sequence as well.
Probably bad form to answer my own question, but Cheeso's answer motivated me to do some lisp programming for the second time in ten years (my original version was a named keyboard macro, but it stepped all over the kill/mark-rings). Here's what I came up with
(defun insert-and-indent-line-above ()
(interactive)
(push-mark)
(let*
((ipt (progn (back-to-indentation) (point)))
(bol (progn (move-beginning-of-line 1) (point)))
(indent (buffer-substring bol ipt)))
(newline)
(previous-line)
(insert indent)))
(global-set-key [ (control return) ] 'insert-and-indent-line-above)
there are probably many better ways of doing this, but two hours of lisp-hacking can hardly be called wasted time :-)