Emacs - Using perform-replace with counter - replace

I'm trying to write a command in elisp to automatically renumber unit tests in a given file. In order to help me easily locate failing tests, I generally use the following syntax (using GoogleTest):
TEST(testCaseName, T0XX_Test_Description)
I've been able to write a working command using a while loop with re-search-forward / replace-match:
(defun renumber-tests-auto(&optional num)
"Automatically renumber the tests from the current location in
the active buffer. Optional argument sets the current test
number (instead of 1). This function automatically updates
all test numbers from the current location until the end of
the buffer without querying the user for each test."
(interactive "NStarting test number: ")
(save-excursion
(setq num (or num 1 ))
(while (re-search-forward ", +T0[0-9]+" nil t )
(replace-match
(concat ", T" (format "%03d" num )))
(setq num (+ 1 num))
)
)
)
However, I'd also really like to have an interactive version of this function, using perform-replace to interactively query the user for each test. I could, of course, simply handle the querying behaviour manually in my code, however, given that this functionality is already present, I don't really want to have to re-implement this. Furthermore, I'd like to ensure that this command has the same interface as the other built-in query-replace functions.
My latest failed attempt follows:
(defun renumber-tests(&optional num)
(interactive "NStarting test number: ")
(save-excursion
(setq num (or num 1 ))
(perform-replace ", +T0[0-9]+"
(concat ", T" (format "%03d" (+ 1 num )
))
t t nil)
)
)
However, this does not update the value of num each time it is run (I also tried (setq num (+ 1 num) ) and got the same result.
I'd greatly appreciate some help from those more experienced in elisp - if there's any way to make it work the way I am intending.

You are calling perform-replacewith a stringas replacement text. You must supply a replacement function to do dynamic replacement. Quote from documentation:
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.
This way you can also get rid of mutation:
(defun renumber-tests(&optional num)
(interactive "NStarting test number: ")
(save-excursion
(perform-replace ", +T0[0-9]+"
(list (lambda (replacement replace-count)
(concat ", T" (format "%03d" (+ replace-count (or num 1))))))
t t nil)))

Related

how to get a list out of list of lists in common lisp

I am new to common lisp and trying to get a list out of a splitted string.
For example:
["4-No 16dia","6-No 20dia"]
Now I want to collect only the third element like ["16","20"]
I have got the splitting part correctly using:
(defun my-split (string &key (delimiterp #'delimiterp)
)
(loop :for beg = (position-if-not delimiterp string)
:then (position-if-not delimiterp string :start (1+ end)
)
:for end = (and beg (position-if delimiterp string :start beg))
:when beg :collect (subseq string beg end)
:while end))
where :
(defun delimiterp (c) (position c " ,-:"))
but collecting only the third element into a list is the tricky part , I have tried:
(defparameter *list1*
(loop for i in (cdr list)
(append (parse-integer
(nth 0
(my-split (nth 3 i)
:delimiterp #'delimiterp))))))
P.S: there are two list cz the example string is itself part of a list-of lists
Please help me, thanks in advance
I would use a regular expression, and I think I would do this largely irrespective of the language that I was using. Of course, some languages don't have regular expressions, but when they do it saves reinventing the wheel.
In Common Lisp, the regular expressions library is called Common Lisp - Practical Perl Compatible Regular Expressions, cl-ppcre. We load this with (ql:quickload "cl-ppcre").
Then the numbers can be returned using (ppcre:scan-to-strings "^(\\d*)-No (\\d*)dia$" x). The regular expression uses \d to pick out a digit, which in Lisp strings is written \\d. The asterisk says return zero or more digits. The parentheses in the regular expression is the bits that we are going to return, the numbers.
Doing this for a list of string is then just using mapcar.
(defparameter text-match "")
(defparameter text-numbers "")
(defparameter test-text '("4-No 16dia" "6-No 23dia"))
(defun extract-numbers (text)
(setf (values text-match text-numbers)
(ppcre:scan-to-strings "^(\\d*)-No (\\d*)dia$" text))
text-numbers)
(defun extract-numbers-from-list (lst)
(mapcar #'extract-numbers lst))
(extract-numbers-from-list test-text) ; => (#("4" "16") #("6" "23"))
Edit: lexical bindings
When I was writing the above, I was trying to get the regular expression right AND trying to get the lexical bindings right at the same time. Having only limited time I put the effort into getting the regular expressions right, and used dynamic variables and setf. OK, it got the job done, but we can do better.
The classical lexical binding system is let, syntax (let ( (var1 val1) (var2 val2) ...) body). We can try (let ((x 0))), which is valid Lisp code, but which doesn't do much. As soon as the lexical scope ends, the variable x is unbound. Attempting to access x causes an error.
We can return multiple values from many functions, such as floor or scan-to-string. We now have to bind these values to variables, using (multiple-value-bind (variable-list) values). Most websites don't really do a good job of explaining this. Having bound the variables, I was getting errors about unbound variables. OK, it's worth just saying -
multiple-value-bind binds variables lexically, just like let.
The full syntax is (multiple-value-bind (variable-list) values body) and your code goes into the body section, just like let. Hence the above code becomes:
(defparameter test-text '("4-No 16dia" "6-No 23dia"))
(defun extract-numbers (text)
(multiple-value-bind (text-match text-numbers)
(ppcre:scan-to-strings "^(\\d*)-No (\\d*)dia$" text)
text-numbers))
(defun extract-numbers-from-list (lst)
(mapcar #'extract-numbers lst))
(extract-numbers-from-list test-text) ; => (#("4" "16") #("6" "23"))
Just to add, cl-ppcre also has register-groups-bind to do regex matching, binding, and converting in a single form:
CL-USER> (cl-ppcre:register-groups-bind ((#'parse-integer no dia))
("(\\d+)-No (\\d+)dia" "4-No 16dia")
(values no dia))
4
16
Without dependencies, one could use:
(defun extract-nums (s)
(mapcar #'(lambda (x) (parse-integer x :junk-allowed t))
(ql-util:split-spaces s)))
And try it with:
(defparameter *s* (list "4-No 16dia" "6-No 20dia"))
(mapcar #'extract-nums *s*)
;; => ((4 16) (6 20))
parse-integer with the setting junk-allowed-p t helps with extracting integer numbers from the string a lot.
But yes, in real-life I would also just use cl-ppcre, e.g.
Mainly the functions cl-ppcre:split and cl-ppcre:scan-to-strings.
(ql:quickload :cl-ppcre)
(defun extract-nums (s)
(mapcar #'parse-integer (cl-ppcre:scan-to-strings "(\\d+)-No (\\d+)dia" s))
And from then on it is just
(second (map #'list (mapcar #'extract-nums *s*))
;; => (16 20)

Read a file into a list of pairs in elisp

I am trying to write an elisp function to read each word in a file into a pair. I want the first item of the pair to be the string sorted lexicographically, and the second item to be untouched.
Given the example file:
cat
cow
dog
I want the list to look like:
(act cat)
(cow cow)
(dgo dog)
My best crack at it is:
(defun get-file (filename)
(with-open-file (stream filename)
(loop for word = (read-line stream nil)
while word
collect ((sort word #'char-lessp) word))))
It compiles correctly in Emacs lisp interaction mode. However, when I try to
run it by executing
(get-file "~/test.txt")
I end up in the Emacs debugger, and it's not telling me anything useful . . .
Debugger entered--Lisp error: (void-function get-file)
(get-file "~/test.txt")
eval((get-file "~/test.txt") nil)
eval-last-sexp-1(t)
eval-last-sexp(t)
eval-print-last-sexp(nil)
call-interactively(eval-print-last-sexp nil nil)
command-execute(eval-print-last-sexp)
I am a lisp beginner, and have no idea what is wrong.
Thanks,
Justin
Vanilla Emacs
First, let's use Emacs's built-in functions only. There's no built-in function to sort strings in Emacs, so you first should convert a string to a list, sort, then convert the sorted list back to a string. This is how you convert a string to a list:
(append "cat" nil) ; => (99 97 116)
A string converted to a list becomes a list of characters, and characters are represented as numbers in Elisp. Then you sort the list and convert it to a string:
(concat (sort (append "cat" nil) '<)) ; => "act"
There's no built-in function to load file contents directly into a variable, but you can load them into a temporary buffer. Then you can return the entire temporary buffer as a string:
(with-temp-buffer
(insert-file-contents-literally "file.txt")
(buffer-substring-no-properties (point-min) (point-max))
This will return the string "cat\ncow\ndog\n", so you'll need to split it:
(split-string "cat\ncow\ndog\n") ; => ("cat" "cow" "dog")
Now you need to traverse this list and convert each item into a pair of sorted item and original item:
(mapcar (lambda (animal)
(list (concat (sort (append animal nil) '<)) animal))
'("cat" "cow" "dog"))
;; returns
;; (("act" "cat")
;; ("cow" "cow")
;; ("dgo" "dog"))
Full code:
(mapcar
(lambda (animal)
(list (concat (sort (append animal nil) '<)) animal))
(split-string
(with-temp-buffer
(insert-file-contents-literally "file.txt")
(buffer-substring-no-properties (point-min) (point-max)))))
Common Lisp Emulation
One of the Emacs built-in packages is cl.el, and there's no reason not to use it in your code. Therefore I lied, when I said there is no built-in functions to sort strings and the above is the only way to do the task using built-in functions. So let's use cl.el.
cl-sort a string (or any sequence):
(cl-sort "cat" '<) ; => "act"
cl-mapcar is more versatile than Emacs's built-in mapcar, but here you can use either of them.
There is a problem with cl-sort, it is destructive, meaning it modifies the argument in-place. We use local variable animal inside the anonymous function twice, and we don't want to garble the original animal. Therefore we should pass a copy of a sequence into it:
(lambda (animal)
(list (cl-sort (copy-sequence animal) '<) animal))
The resulting code becomes:
(cl-mapcar
(lambda (animal)
(list (cl-sort (copy-sequence animal) '<) animal))
(split-string
(with-temp-buffer
(insert-file-contents-literally "file.txt")
(buffer-substring-no-properties (point-min) (point-max)))))
seq.el
In Emacs 25 a new sequence manipulation library was added, seq.el. Alternative to mapcar is seq-map, alternative to CL's cl-sort is seq-sort. The full code becomes:
(seq-map
(lambda (animal)
(list (seq-sort animal '<) animal))
(split-string
(with-temp-buffer
(insert-file-contents-literally "file.txt")
(buffer-substring-no-properties (point-min) (point-max)))))
dash, s, f
Usually the best solution to work with sequences and files is to reach directly for these 3 third-party libraries:
dash for list manipulation
s for string manipulation
f for file manipulation.
Their Github pages explain how to install them (installation is very simple). However for this particular problem they are a bit suboptimal. For example, -sort from dash only sorts lists, so we would have to get back to our string->list->string conversion:
(concat (-sort '< (append "cat" nil))) ; => "act"
s-lines from s leaves empty strings in files. On GNU/Linux text files usually end with newline at the end, so splitting your file would look like:
(s-lines "cat\ncow\ndog\n") ; => ("cat" "cow" "dog" "")
s-split supports an optional argument to omit empty lines, but it's separator argument is a regex (note that you need both \n and \r for portability):
(s-split "[\n\r]" "cat\ncow\ndog\n" t) ; => ("cat" "cow" "dog")
Yet there are 2 functions which can simplify our code. -map is similar to mapcar:
(-map
(lambda (animal)
(list (cl-sort (copy-sequence animal) '<) animal))
'("cat" "cow" "dog"))
;; return
;; (("act" "cat")
;; ("cow" "cow")
;; ("dgo" "dog"))
However in dash there are anaphoric versions of functions that accept a function as an argument, such as -map. Anaphoric versions allow to use shorter syntax by exposing local variable as it and start with 2 dashes. E.g. the below are equivalent:
(-map (lambda (x) (+ x 1)) (1 2 3)) ; => (2 3 4)
(--map (+ it 1) (1 2 3)) ; => (2 3 4)
Another improvement is f-read-text from f, which simply returns contents of a file as a string:
(f-read-text "file.txt") ; => "cat\ncow\ndog\n"
Combine best of all worlds
(--map (list (cl-sort (copy-sequence it) '<) it)
(split-string (f-read-text "file.txt")))
On my emacs, either C-j or C-x C-e evaluates the form as you said. When I try to do the same with (get-file "test") the debugger complains about with-open-file being undefined. I cannot find with-open-file in cl-lib (or cl) emacs packages.
Did you require some other package? Also, I think the idiomatic way of opening file in Emacs is to temporary visit them in buffers.
Anyway, if the code was Common Lisp it would be ok except for collect ((sort ...) word), where you are not building a list but using (sort ...) in a function position. I'd use (list (sort ...) word) instead.

emacs org mode, search only headers

In emacs, I want to be able to search only the 'headers' in an org mode file.
Idea 1: Search only Visible
I could achieve this by hiding everything, then showing only the outline (S-TAB, S-TAB) and then maybe search all that is visible.(in this case it would be the whole table of content).
But how do I search only visible content? C-s searches everything.
Idea 2: use regex
I can potentially do:
C-c / / //opens regex search
\*.*heading //start with * (escaped), followed by any chars, then heading.
But at the moment it's cumbersome to type all of that. Considering I've started learning emacs like 3 hours ago, can I automate this somehow?
E.g, can I write a function to search with "*.*ARGUMENT" and tie it a hotkey? but still have the ability to go like 'next find, next find' etc..?
The use case for this is searching my notes. Some are like ~7000+ lines long and I commonly only search the headers.
[EDIT Solution 1]
#abo-abo's answer worked well for me. I now use helm-org-in-buffer-headings
I.e, I installed Melpa:
https://github.com/milkypostman/melpa#usage
Then I installed helm from the package list:
M-x package-list-packages
Then I edited my .emacs and bound a hotkey to it:
(global-set-key (kbd "C-=") 'helm-org-in-buffer-headings) ;Outline search.
I reloaded emacs and now when pressing Ctrl+= a searchable outline pops up that automatically narrows down as I type in additional characters. The usual C-n, C-p , buttons work for navigation.
Thanks!
[Edit Solution 2]
Curiosity got the best of me. After enjoying helm's heading search, I messed around with worf also. It is like helm (it uses helm) but looks nicer and I can select a 'level' of outline by pressing the number key. I hacked out just the bits necessary for heading search, if of use:
;; ——— WORF Utilities ———————————————————————————————————————————————————————————————
;; https://github.com/abo-abo/worf/blob/master/worf.el
(defun worf--pretty-heading (str lvl)
"Prettify heading STR or level LVL."
(setq str (or str ""))
(setq str (propertize str 'face (nth (1- lvl) org-level-faces)))
(let (desc)
(while (and (string-match org-bracket-link-regexp str)
(stringp (setq desc (match-string 3 str))))
(setq str (replace-match
(propertize desc 'face 'org-link)
nil nil str)))
str))
(defun worf--pattern-transformer (x)
"Transform X to make 1-9 select the heading level in `worf-goto'."
(if (string-match "^[1-9]" x)
(setq x (format "^%s" x))
x))
(defun worf-goto ()
"Jump to a heading with `helm'."
(interactive)
(require 'helm-match-plugin)
(let ((candidates
(org-map-entries
(lambda ()
(let ((comp (org-heading-components))
(h (org-get-heading)))
(cons (format "%d%s%s" (car comp)
(make-string (1+ (* 2 (1- (car comp)))) ?\ )
(if (get-text-property 0 'fontified h)
h
(worf--pretty-heading (nth 4 comp) (car comp))))
(point))))))
helm-update-blacklist-regexps
helm-candidate-number-limit)
(helm :sources
`((name . "Headings")
(candidates . ,candidates)
(action . (lambda (x) (goto-char x)
(call-interactively 'show-branches)
(worf-more)))
(pattern-transformer . worf--pattern-transformer)))))
And then tied it to a hot key:
(global-set-key (kbd "<f3>") 'worf-goto)
worf-goto from worf can do this,
so can helm-org-in-buffer-headings from helm.
worf-goto actually uses helm as a back end. In addition to helm-org-in-buffer-headings, you get:
headings are colored in the same way as in the original buffer
you can select all headings with the same level using the appropriate digit
If you have ivy installed, you can use counsel-org-goto to search headings in the current buffer or counsel-org-goto-all to search the headings in all open org-mode buffers.
It's a good option if you don't want to install the other things that come with worf.
If you don't want to rely on external packages, org, in fact, already offers this capability: the function is org-goto.
If you want it to behave in a way similar to helm-org-in-buffer-headings, you have to set org-goto-interface to outline-path-completion, for instance by adding to your init file:
(setq org-goto-interface (quote outline-path-completion))

Scheme filters - "wrong value to apply: #f"

I'm trying to filter out a list based off of a predicate I wrote myself, but when I run the filter, I get
ERROR: Wrong value to apply: #f
The code of the predicate:
;;;Predicate for checking if a string is not empty or full of whitespaces
(define (notwhitespace? str)
(if (equal? str "") #F (
(call-with-current-continuation
(lambda (return)
(for-each
(lambda (c)
(if (not (char-whitespace? c)) #T #F))
(string->list str))
#F))
)
)
)
this is my implementation of the filter (it is in a let statement):
(updated-strlist(filter notwhitespace? strlist))
any ideas? thanks!
So (call-with-current-continuation ...) in your code is wrappen in extra parentheses which means that Scheme should take the result and run it as a procedure the moment it gets it.
Usually in a LISP evaluator apply is the procedure that runs procedures. eg.
(define (test) (display "hello"))
(define (get-proc) test)
((get-proc)) ; ==> undefined, displays "hello"
You code however tries to do this (#f) and since #f is not a procedure apply cannot run it as if it were one.
A comment on the rest there. If you are not using return you really shouldn't use call-with-current-continuation at all and for-each does sonething entirely different than you think. nowhitespace? will always evaluate to #f when you've fixed your problems because the last expression in the body of the continuation lambda is #f (the returned value).
I guess you are looking for something like:
;; needs to import (srfi :1)
(define (notwhitespace? str)
(every (lambda (x) (not (char-whitespace? x)))
(list->string str)))
;; needs to import (srfi :13)
(define (notwhitespace2? str)
(not (string-index str char-whitespace?)))
Don't write (#f), it should be #f.

Finding out which regexp caused a specific face in Emacs

I am trying to find out which regexp causes the connect to be highlighted in this cperl-mode buffer. describe-face tells me this is a font-lock-type-face. After having a look at font-lock-keywords-alist and font-lock-keywords I dont't see where this highlight could have come from. The colorful parantheses are created by the rainbow-delimiters-mode.
Is there a function to check which regexp matched, such that connect is highlighted with this face?
I had a local font-lock hack to record in the buffer the rule that was used. The patch below might do it. Once you've applied it (and reloaded font-lock.el), you can check (with C-u C-x =) the font-lock-debug property on the buffer position whose fontification you want to understand.
=== modified file 'lisp/font-lock.el'
--- lisp/font-lock.el 2013-01-11 23:08:55 +0000
+++ lisp/font-lock.el 2013-01-13 15:28:16 +0000
## -1563,6 +1611,14 ##
;;; Keyword regexp fontification functions.
+(defvar font-lock-debug nil)
+
+(defun font-lock-debug ()
+ (interactive)
+ (set (make-local-variable 'font-lock-debug) t)
+ (make-local-variable 'font-lock-extra-managed-props)
+ (push 'font-lock-debug font-lock-extra-managed-props))
+
(defsubst font-lock-apply-highlight (highlight)
"Apply HIGHLIGHT following a match.
HIGHLIGHT should be of the form MATCH-HIGHLIGHT, see `font-lock-keywords'."
## -1577,13 +1633,16 ##
(when (eq (car-safe val) 'face)
(add-text-properties start end (cddr val))
(setq val (cadr val)))
- (cond
- ((not (or val (eq override t)))
+ (if (and (not val) (not (eq override t)))
;; If `val' is nil, don't do anything. It is important to do it
;; explicitly, because when adding nil via things like
;; font-lock-append-text-property, the property is actually
;; changed from <face> to (<face>) which is undesirable. --Stef
- nil)
+ nil
+ (if font-lock-debug
+ (font-lock-append-text-property start end 'font-lock-debug
+ (list (cons matcher highlight))))
+ (cond
((not override)
;; Cannot override existing fontification.
(or (text-property-not-all start end 'face nil)
## -1599,7 +1658,7 ##
(font-lock-append-text-property start end 'face val))
((eq override 'keep)
;; Keep existing fontification.
- (font-lock-fillin-text-property start end 'face val)))))))
+ (font-lock-fillin-text-property start end 'face val))))))))
(defsubst font-lock-fontify-anchored-keywords (keywords limit)
"Fontify according to KEYWORDS until LIMIT.
## -1621,6 +1680,7 ##
(min lead-start (point)))
limit
'font-lock-multiline t)))
+ (font-lock-append-text-property (point) limit 'font-lock-debug keywords)
(save-match-data
;; Find an occurrence of `matcher' before `limit'.
(while (and (< (point) limit)
I know of no such function. The regular expressions are compiled to be optimal, why do you need to know?
BTW, displaying font-lock-keyword shows the string nect just besides tinue.
Did you try font-lock studio? It works great for me.