setting a regular expression into the emacs header line - regex

So I'm new to emacs lisp, and I've got a long file with walls of text broken up by dates. Sometimes I can't see what date I'm reading under without scrolling up and losing my position, and I decided I wanted to be able to see this at all times.
After skim-reading the manuals, borrowing code examples and making a wild stab in the dark, the following worked beautifully:
(add-hook 'text-mode-hook
(lambda ()
(setq header-line-format
'(:eval
;;(setq temp-point point)
(setq temp-string
(if (re-search-backward "../../.." nil t nil) (match-string 0) '("no date"))
)
;;(goto-char 'temp-point)
`(temp-string)
)
)
)
)
There's only one fly in the ointment: re-search-backward moves the point. I want it to stay put.
First of all, is there a function that can do a regexp search without moving the point and return the match?
Secondly, and whether or not that's true: as you can tell from the commented code I've been trying to work around it by saving the value of point and then resetting the position afterward. The order of the code is on the assumption that the last element of the list is the one that gets returned.
However that assumption doesn't seem to always hold: as soon as I uncomment the first line (which can actually be anything as long as it's valid code) the header gets set to a blank string instead.
If someone could tell me where I'm going wrong, that would be great. Also if I've got any bad habits or less-than-efficient ways of solving a problem, please point them out.

You're looking for the save-excursion macro. Wrap it around your search, and it will undo any movement. To quote the docstring:
(save-excursion &rest BODY)
Save point, mark, and current buffer; execute BODY; restore those things.
So in place of (re-search-backward "../../.." nil t nil) you'd put:
(save-excursion
(re-search-backward "../../.." nil t nil))
As to why uncommenting the first line would change the result, this has to do with the way :eval works in mode/header line format specs. The docstring for mode-line-format says that it's (:eval FORM) - with just one form - and apparently it silently ignores any forms after the first one. (Your intuition is correct: most of the time the last value inside the form is returned, and the behaviour of :eval is indeed surprising.)

Related

manipulate regexp-search matches using `query-regexp-replace` in a defun

Since version 22 of Emacs, we can use \,(function) for manipualting (parts of) the regex-search result before replacing it. But – this is mentioned often, but nonetheless still the truth – we can use this construct only in the standard interactive way. (Interactive like: By pressing C-M-% or calling query-replace-regexp with M-x.)
As an example:
If we have
[Foo Bar 1900]
and want to get
[Foo Bar \function{foo1900}{1900}]
we can use:
M-x query-replace-regexp <return>
\[\([A-Za-z-]+\)\([^0-9]*\) \([0-9]\{4\}\)\]
[\1\2 \\function{\,(downcase \1)\3}{\3}]
to get it done. So this can be done pretty easy.
In my own defun, I can use query only by replacing without freely modifying the match, or modify the prepared replaced string without any querying. The only way I see, is to serialize it in such a way:
(defun form-to-function ()
(interactive)
(goto-char (point-min))
(while (query-replace-regexp
"\\[\\([A-Za-z-]+\\)\\([^0-9]*\\) \\([0-9]\\{4\\}\\)\\]"
"[\\1\\2 \\\\function{\\1\\3}{\\3}]" ))
(goto-char (point-min))
(while (search-forward-regexp "\\([a-z0-9]\\)" nil t)
(replace-match (downcase (match-string 1)) t nil)
)
)
For me the query is important, because I can't be sure, what the buffer offers me (= I can't be sure, the author used this kind of string always in the same manner).
I want to use an elisp function, because it is not the only recurring replacement (and also not only one buffer (I know about dired-do-query-replace-regexp but I prefer working buffer-by-buffer with replace-defuns)).
At first I thought I only miss something like a query-replace-match to use instead of replace-match. But I fear, I am also missing the easy and flexible way of rearrange the string the the query-replace-regexp.
So I think, I need a \, for use in an defun. And I really wonder, if I am the only one, who is missing this feature.
If you want your rsearch&replace to prompt the user, that means you want it to be interactive, so it's perfectly OK to call query-replace-regexp (even if the byte-compiler will tell you that this is meant for interactive use only). If the warning bothers you, you can either wrap the call in with-no-warnings or call perform-replace instead.
The docstring of perform-replace sadly doesn't (or rather "didn't" until today) say what is the format of the replacements argument, but you can see it in the function's code:
;; REPLACEMENTS is either a string, a list of strings, or a cons cell
;; containing a function and its first argument. The function is
;; called to generate each replacement like this:
;; (funcall (car replacements) (cdr replacements) replace-count)
;; It must return a string.
The query-replace-function can handle replacement not only as a string, but as a list including the manipulating elements. The use of concat archives building an string from various elements.
So one who wants to manipulate the search match by a function before inserting the replacement can use query-replace-regexp also in a defun.
(defun form-to-function ()
(interactive)
(goto-char (point-min))
(query-replace-regexp
"\\[\\([A-Za-z-]+\\)\\([^0-9]*\\) \\([0-9]\\{4\\}\\)\\]"
(quote (replace-eval-replacement concat "[\\1\\2 \\\\function{"
(replace-quote (downcase (match-string 1))) "\\3}{\\3}]")) nil ))
match-string 1 returns the first expression of our regexp-search.
`replace-quote' helps us doublequoting the following expression.
concat forms a string from the following elements.
and
replace-eval-replacement is not documented.
Why it is in use here nevertheless, is because of emacs seems to use it internally, while performing the first »interactive« query-replace-regexp call. At least is it given by asking emacs with repeat-complex-command.
I came across repeat-complex-command (bound to [C-x M-:].) while searching for an answer in the source code of query-replace-regexp.
So an easy to create defun could be archieved by performing the standard search and replace way as told in the question and after first sucess pressing [C-x M-:] results in an already Lisp formed command, which can be copied and pasted in a defun.
Edit (perform-replace)
As Stefan mentioned, one can use perform-replace to avoid using query-replace-regexp.
Such a function could be:
(defun form-to-function ()
(interactive)
(goto-char (point-min))
(while (perform-replace
"\\[\\([A-Za-z-]+\\)\\([^0-9]*\\) \\([0-9]\\{4\\}\\)\\]"
(quote (replace-eval-replacement concat "[\\1\\2 \\\\function{"
(replace-quote (downcase (match-string 1))) "\\3}{\\3}]"))
t t nil)))
The first boolean (t) is a query flag, the second is the regexp switch. So it works also perfectly, but it didn't help finding the replacement expression as easy as in using \,.

Emacs Lisp and non-deterministic regexes

I've been spending too much time lately trying to debug some auto-complete-mode functionality in Emacs, this function appears to be non-deterministic and has left me utterly confused.
(re-search-backward "\\(\\sw\\|\\s_\\|\\s\\.\\|\\s\\\\|[##|]\\)\\=")
The command is called in a while loop, searching backwards from the current point to find the full "word" that should be autocompleted. For reference, the actual code.
A bit of background and my investigations
I have been trying to setup autocompletion for Javascript, using slime to connect to a Node.js backend.
Autocomplete inside a Slime REPL connected to a Node.js backend is perfect,
Autocomplete inside a js2-mode buffer, connected to Slime, is failing to look up completions from slime. In this image you can see it falling back to the words already in the buffer.
I've tracked this down to Slime's slime-beginning-of-symbol function.
Assume that I'm trying to complete fs.ch where fs has been required and is in scope already, the point is located on after the h character.
In the slime repl buffer the beginning function moves the point all of the way back until it hits whitespace and matches fs.ch.
In the js2-mode buffer the beginning function moves the point only to the dot character and matches only ch.
Reproducing the problem
I've been testing this by evaling (re-search-backward "\\(\\sw\\|\\s_\\|\\s\\.\\|\\s\\\\|[##|]\\)\\=") repeatedly in various buffers. For all examples, the point starts at the end of the line and moves backwards until the search fails.
In the scratch buffer fs.ch the point ends on the c.
In the slime repl fs.ch the point ends on the f.
In the js2-mode buffer fs.ch the point ends on the c.
In an emacs-lisp-mode buffer fs.ch the point ends on the f.
I have no idea why this is happening
I'm going to assume that there's something in these modes that either sets or unsets a global regex var that then has this effect, but so far I've been unable to find or implicate anything.
I even tracked this down to the emacs c code, but at that point realised that I was in completely over my head and decided to ask for help.
Help?
You should replace \\s\\. with \\s. in your regexp.
I "fixed" the problem by redefining the source that gets added to auto complete's ac-sources.
I'm still learning my way around elisp so this is likely the most hack-like way of achieving what I need, but it works.
I changed the regex from:
\\(\\sw\\|\\s_\\|\\s\\.\\|\\s\\\\|[##|]\\)\\=
to
\\(\\sw\\|\\s_\\|\\s.\\|\\s\\\\|[##|]\\)\\=
(note the change of \\s\\.\\ to \\s.\\).
And then overrode the auto-complete setup in my init.el. (I'll probably find a hundred ways to refine this when I actually know elisp).
(defun js-slime-beginning-of-symbol ()
"Move to the beginning of the CL-style symbol at point."
(while (re-search-backward "\\(\\sw\\|\\s_\\|\\s.\\|\\s\\\\|[##|]\\)\\="
(when (> (point) 2000) (- (point) 2000))
t))
(re-search-forward "\\=#[-+.<|]" nil t)
(when (and (looking-at "#") (eq (char-before) ?\,))
(forward-char)))
(defun js-slime-symbol-start-pos ()
"Return the starting position of the symbol under point.
The result is unspecified if there isn't a symbol under the point."
(save-excursion (js-slime-beginning-of-symbol) (point)))
(defvar ac-js-source-slime-simple
'((init . ac-slime-init)
(candidates . ac-source-slime-simple-candidates)
(candidate-face . ac-slime-menu-face)
(selection-face . ac-slime-selection-face)
(prefix . js-slime-symbol-start-pos)
(symbol . "l")
(document . ac-slime-documentation)
(match . ac-source-slime-case-correcting-completions))
"Source for slime completion.")
(defun set-up-slime-js-ac (&optional fuzzy)
"Add an optionally-fuzzy slime completion source to `ac-sources'."
(interactive)
(add-to-list 'ac-sources ac-js-source-slime-simple))
In response to my own question about regex global state. There is a lot of it.
Emacs regexes use syntax tables defined in the major mode to determine which characters to match. The reason I was seeing the dot match in the lisp mode but not the js mode was because of different definitions. In the lisp mode '.' is defined as symbol, in js2-mode '.' is defined as punctuation.
As a consequence, an alternative way to fix the problem is to redefine .'s syntax in js2-mode. I tried this out and redefined . as a word with (modify-syntax-entry ?. "w"). However I decided not to stay with that result because it will probably break something down the line.
Also, I have to thank the people in #emacs, they really helped me out on this, teaching me about syntax tables and the horrors of elisp regex globals.

Emacs Brace and Bracket Highlighting?

When entering code Emacs transiently highlights the matching brace or bracket. With existing code however is there a way to ask it to highlight a matching brace or bracket if I highlight its twin?
I am often trying to do a sanity check when dealing with compiler errors and warnings. I do enter both braces usually when coding before inserting the code in between, but have on occasion unintentionally commented out one brace when commenting out code while debugging.
Any advice with dealing with brace and bracket matching with Emacs?
OS is mostly Linux/Unix, but I do use it also on OS X and Windows.
If you're dealing with a language that supports it, give ParEdit a serious look. If you're not using with a Lisp dialect, it's not nearly as useful though.
For general brace/bracket/paren highlighting, look into highlight-parentheses mode (which color codes multiple levels of braces whenever point is inside them). You can also turn on show-paren-mode through customizations (that is M-x customize-variable show-paren-mode); that one strongly highlights the brace/bracket/paren matching one at point (if the one at point doesn't match anything, you get a different color).
my .emacs currently contains (among other things)
(require 'highlight-parentheses)
(define-globalized-minor-mode global-highlight-parentheses-mode highlight-parentheses-mode
(lambda nil (highlight-parentheses-mode t)))
(global-highlight-parentheses-mode t)
as well as that show-paren-mode customization, which serves me well (of course, I also use paredit when lisping, but these are still marginally useful).
Apart from the answer straight from the manual or wiki, also have a look at autopair.
tried on emacs 26
(show-paren-mode 1)
(setq show-paren-style 'mixed)
enable showing parentheses
set the showing in such as highlit the braces char., or if either one invisible higlight what they enclose
for toggling the cursor position / point between both, put this script in .emacs
(defun swcbrace ()(interactive)
(if (looking-at "(")(forward-list)
(backward-char)
(cond
((looking-at ")")(forward-char)(backward-list))
((looking-at ".)")(forward-char 2)(backward-list))
)))
(global-set-key (kbd "<C-next>") 'swcbrace)
it works toggling by press Control-Pgdn
BTW, for the immediate question: M-x blink-matching-open will "re-blink" for an existing close paren, as if you had just inserted it. Another way to see the matching paren is to use M-C-b and M-C-f (which jump over matched pairs of parens), which are also very useful navigation commands.
I second ParEdit. it is very good atleast for lisp development.
FWIW I use this function often to go to matching paren (back and forth).
;; goto-matching-paren
;; -------------------
;; If point is sitting on a parenthetic character, jump to its match.
;; This matches the standard parenthesis highlighting for determining which
;; one it is sitting on.
;;
(defun goto-matching-paren ()
"If point is sitting on a parenthetic character, jump to its match."
(interactive)
(cond ((looking-at "\\s\(") (forward-list 1))
((progn
(backward-char 1)
(looking-at "\\s\)")) (forward-char 1) (backward-list 1))))
(define-key global-map [(control ?c) ?p] 'goto-matching-paren) ; Bind to C-c p
Declaimer: I am NOT the author of this function, copied from internet.
If you just want to check the balanced delimiters, be them parentheses, square brackets or curly braces, you can use backward-sexp (bound to CtrlAltB) and forward-sexp (bound to CtrlAltF) to skip backward and forward to the corresponding delimiter. These commands are very handy to navigate through source files, skipping structures and function definitions, without any buffer modifications.
You can set the below in your init.el:
(setq show-paren-delay 0)
(show-paren-mode 1)
to ensure matching parenthesis are highlighted.
Note that (setq show-paren-delay 0) needs to be set before (show-paren-mode 1) so that there's no delay in highlighting, as per the wiki.
If you want to do a quick check to see whether brackets in the current file are balanced:
M-x check-parens
Both options tested on Emacs 27.1

Emacs compilation-mode regex for multiple lines

So I have a tool lints python changes I've made and produces errors and warnings. I would like this to be usable in compile mode with Emacs, but I have an issue. The file name is output only once at the beginning, and then only line numbers appear with the errors and warnings. Here's an example:
Linting file.py
E0602: 37: Undefined variable 'foo'
C6003: 42: Unnecessary parens after 'print' keyword
2 new errors, 2 total errors in file.py.
It's very similar to pylint, but there's no output-format=parseable option. I checked the documentation for compilation-error-regexp-alist, and found something promising:
If FILE, LINE or COLUMN are nil or that index didn't match, that
information is not present on the matched line. In that case the
file name is assumed to be the same as the previous one in the
buffer, line number defaults to 1 and column defaults to
beginning of line's indentation.
So I tried writing a regexp that would optionally match the file line and pull it out in a group, and then the rest would match the other lines. I assumed that it would first match
Linting file.py
E0602: 37: Undefined variable 'foo'
and be fine. Then it would continue and match
C6003: 42: Unnecessary parens after 'print' keyword
with no file. Since there was no file, it should use the file name from the previous match right? Here's the regexp I'm using:
(add-to-list 'compilation-error-regexp-alist 'special-lint)
(add-to-list 'compilation-error-regexp-alist-alist
'(special-lint
"\\(Linting \\(.*\\)\\n\\)?\\([[:upper:]][[:digit:]]+:\\s-+\\([[:digit:]]\\)+\\).*"
2 4 nil nil 3))
I've checked it with re-builder and manually in the scratch buffer. It behaves as expected. the 2nd group is the file name, the 4th is the line number, and the 3rd is what I want highlighted. Whenever I try this, I get the error:
signal(error ("No match 2 in highlight (2 compilation-error-face)"))
I have a workaround for this that involves transforming the output before the compile module looks at it, but I'd prefer to get rid of that and have a "pure" solution. I would appreciate any advice or pointing out any dumb mistakes I may have made.
EDIT
Thomas' pseudo code below worked quite well. He mentioned that doing a backwards re search could mess up the match data, and it did. But that was solved by adding the save-match-data special form before save-excursion.
FILE can also have the form (FILE
FORMAT...), where the FORMATs (e.g.
"%s.c") will be applied in turn to the
recognized file name, until a file of
that name is found. Or FILE can also
be a function that returns (FILENAME)
or (RELATIVE-FILENAME . DIRNAME). In
the former case, FILENAME may be
relative or absolute.
You could try to write a regex that doesn't match the file name at all, only the column. Then for the file, write a function that searches backwards for the file. Perhaps not as efficient, but it should have the advantage that you can move upwards through the error messages and it will still identify the correct file when you cross file boundaries.
I don't have the necessary stuff installed to try this out, but take the following pseudo-code as an inspiration:
(add-to-list 'compilation-error-regexp-alist-alist
'(special-lint
"^\\S-+\\s-+\\([0-9]+\\):.*" ;; is .* necessary?
'special-lint-backward-search-filename 1))
(defun special-lint-backward-search-filename ()
(save-excursion
(when (re-search-backward "^Linting \\(.*\\)$" (point-min) t)
(list (match-string 1)))))
(It could be that using a search function inside special-lint-backward-search-filename will screw up the sub-group matching of the compilation-error-regexp, which would suck.)
I don't think you can make compilation do what you want here, because it won't assume that a subsequent error relates to a previously-seen filename. But here's an alternative; write a flymake plugin. Flymake always operates on the current file, so you only need to tell it how to find line (and, optionally, column) numbers.
Try hacking something like this, and you'll likely be pleasantly surprised.

in emacs-lisp, how do I correctly use replace-regexp-in-string?

Given a string, I want to replace all links within it with the link's description. For example, given
this is a [[http://link][description]]
I would like to return
this is a description
I used re-builder to construct this regexp for a link:
\\[\\[[^\\[]+\\]\\[[^\\[]+\\]\\]
This is my function:
(defun flatten-string-with-links (string)
(replace-regexp-in-string "\\[\\[[^\\[]+\\]\\[[^\\[]+\\]\\]"
(lambda(s) (nth 2 (split-string s "[\]\[]+"))) string))
Instead of replacing the entire regexp sequence, it only replaces the trailing "]]". This is what it produces:
this is a [[http://link][descriptiondescription
I don't understand what's going wrong. Any help would be much appreciated.
UPDATE: I've improved the regex for the link. It's irrelevant to the question but if someone's gonna copy it they may as well get the better version.
Your problem is that split-string is clobbering the match data, which
replace-regexp-in-string is relying on being unchanged, since it is going to
go use that match data to decide which sections of the string to cut out. This
is arguably a doc bug in that replace-regexp-in-string does not mention that
your replacement function must preserve the match data.
You can work around by using save-match-data, which is a macro provided for
exactly this purpose:
(defun flatten-string-with-links (string)
(replace-regexp-in-string "\\[\\[[a-zA-Z:%#/\.]+\\]\\[[a-zA-Z:%#/\.]+\\]\\]"
(lambda (s) (save-match-data
(nth 2 (split-string s "[\]\[]+")))) string))