How to define a function which repeats itself when passed an argument - emacs

Is there an easy way to define a function which repeats itself when passed an argument?
For example, I've defined the following function
(defun swap-sign ()
(interactive)
(search-forward-regexp "[+-]")
(if (equal (match-string 0) "-")
(replace-match "+")
(replace-match "-"))
)
I'd like C-u swap-sign to call swap-sign four times.
I've tried
(defun swap-sign (&optional num)
(interactive)
(let ((counter 0)
(num (if num (string-to-number num) 0)))
(while (<= counter num)
(search-forward-regexp "[+-]")
(if (equal (match-string 0) "-")
(replace-match "+")
(replace-match "-"))
(setq counter (1+ counter)))))
but C-u swap-sign still only runs swap-sign (or perhaps more precisely, the body of the while-loop) once. I'm guessing it is because if num is not the right way to test if num is an empty string.
Am I on the right track, or is there a better/easier way to extend swap-sign?

(defun swap-sign (arg)
(interactive "p")
(dotimes (i arg)
(search-forward-regexp "[+-]")
(if (equal (match-string 0) "-")
(replace-match "+")
(replace-match "-"))))
See the documentation of the interactive special form for more details:
C-h finteractiveRET.

You need to tell emacs to expect, and pass the parameter in, by adding a "p" as the parameter specification for interactive (M-x apropos interactive to get the documentation). Here I've made the minimal change to your code to get it to work - note, however, that you don't need the let/while to do the iteration, and the arg doesn't need to be optional.
(defun swap-sign (&optional num)
(interactive "p")
(let ((counter 1))
(while (<= counter num)
(search-forward-regexp "[+-]")
(if (equal (match-string 0) "-")
(replace-match "+")
(replace-match "-"))
(setq counter (1+ counter)))))
Note that you don't need to convert the parameter from a string - using "p" tells emacs to do this for you.

Related

Emacs. Specific formatting autopair for "{"

I have found many ways to automatically insert "}" after typing "{" but never found the following implementation:
After typing "{" it moved on the next line (with indented if necessary), next is an empty string with the cursor, and "}" on the next line:
if (i == 0)*here we typing "{"*
and get the following:
if (i == 0)
{
|
}
and for nested brackets:
if (i == 0)
{
if (j == 0)
{
|
}
}
How to do this?
Note: I already use yasnipped but it does not work for functions.
If you are using electric-pair-mode, you can supply your own function:
(defun my-electric-pair-open-newline-between-pairs()
"Indent paired char and empty line"
(when (and (eq last-command-event ?\n)
(< (1+ (point-min)) (point) (point-max))
(eq (save-excursion
(skip-chars-backward "\t\s")
(char-before (1- (point))))
(matching-paren (char-after))))
(save-excursion
(insert "\n")
(indent-according-to-mode))
(indent-according-to-mode))
nil)
(setq-default electric-pair-open-newline-between-pairs 'my-electric-pair-open-newline-between-pairs)
(electric-pair-mode 1)
It will do what you describe only if you hit return between empty brackets.
I did something similar to this to try to emulate Eclipse's newline functionality.
(defun my-newline ()
(interactive)
(let ((s (buffer-substring (point-at-bol) (point))))
(cond
((string-match ".*{$" s) ; matching a line ending with {
(move-end-of-line nil)
(insert "}") ; insert }. Can be removed if already being inserted
(backward-char 2)
(newline-and-indent)
(forward-char)
(newline-and-indent)
(move-beginning-of-line nil)
(backward-char 1)
(newline-and-indent))
(t (newline-and-indent)))))
You can then attach it to whatever keybinding you like. I overrode C-j as that was what I was used to.
(defun my-newline-hook ()
(local-set-key (kbd "C-j") 'my-newline))
(add-hook 'java-mode-hook 'my-java-hook)
The regex and steps taken can be adjusted to fit your needs.

Is there a way to toggle a string between single and double quotes in emacs?

I'm looking for an emacs command that will toggle the surrounding quote characters on the string under the point, e.g. with the cursor in the string 'bar', hit a key and change it between:
foo = 'bar' <---> foo = "bar"
For bonus points it would:
handle toggling Python triple-quote strings (''' <---> """)
automatically change backslash escaping inside the string as appropriate.
e.g.
foo = 'bar "quote"' <---> foo = "bar \"quote\""
This could be a bit more robust:
(defun toggle-quotes ()
(interactive)
(save-excursion
(let ((start (nth 8 (syntax-ppss)))
(quote-length 0) sub kind replacement)
(goto-char start)
(setq sub (buffer-substring start (progn (forward-sexp) (point)))
kind (aref sub 0))
(while (char-equal kind (aref sub 0))
(setq sub (substring sub 1)
quote-length (1+ quote-length)))
(setq sub (substring sub 0 (- (length sub) quote-length)))
(goto-char start)
(delete-region start (+ start (* 2 quote-length) (length sub)))
(setq kind (if (char-equal kind ?\") ?\' ?\"))
(loop for i from 0
for c across sub
for slash = (char-equal c ?\\)
then (if (and (not slash) (char-equal c ?\\)) t nil) do
(unless slash
(when (member c '(?\" ?\'))
(aset sub i
(if (char-equal kind ?\") ?\' ?\")))))
(setq replacement (make-string quote-length kind))
(insert replacement sub replacement))))
It will use syntax information from the buffer to find the quotes at the beginning of the string (that is given that the strings are quoted), and will also try to flip quotes inside the string, unless they are escaped with backslash - which looks like it could be a common case.
PS. I've just realized you also wanted it to find triple quotes, so her goes.
Here's a quick hack to get you started:
(defun toggle-quotes ()
"Toggle single quoted string to double or vice versa, and
flip the internal quotes as well. Best to run on the first
character of the string."
(interactive)
(save-excursion
(re-search-backward "[\"']")
(let* ((start (point))
(old-c (char-after start))
new-c)
(setq new-c
(case old-c
(?\" "'")
(?\' "\"")))
(setq old-c (char-to-string old-c))
(delete-char 1)
(insert new-c)
(re-search-forward old-c)
(backward-char 1)
(let ((end (point)))
(delete-char 1)
(insert new-c)
(replace-string new-c old-c nil (1+ start) end)))))
The function swaps the internal quotes to the opposite, which is close to bonus 2.
Here's something even more robust, in that it doesn't delete the whole text between the quotes (doing so prevents save-excursion from keeping the point where it was, which is a pain). Also handles (un)backslash-ing nested quotes.
(defun toggle-quotes ()
(interactive)
(let* ((beg (nth 8 (syntax-ppss)))
(orig-quote (char-after beg))
(new-quote (case orig-quote
(?\' ?\")
(?\" ?\'))))
(save-restriction
(widen)
(save-excursion
(catch 'done
(unless new-quote
(message "Not inside a string")
(throw 'done nil))
(goto-char beg)
(delete-char 1)
(insert-char new-quote)
(while t
(cond ((eobp)
(throw 'done nil))
((= (char-after) orig-quote)
(delete-char 1)
(insert-char new-quote)
(throw 'done nil))
((= (char-after) ?\\)
(forward-char 1)
(when (= (char-after) orig-quote)
(delete-char -1))
(forward-char 1))
((= (char-after) new-quote)
(insert-char ?\\)
(forward-char 1))
(t (forward-char 1)))))))))
Here's a function I made for JavaScript, might help?
function swap_str(e, r, t) {
return e = e.split(r).join("WHAK_a_SWAP"), e = e.split(t).join("WHAK_b_SWAP"), e = e.split("WHAK_a_SWAP").join(t),
e = e.split("WHAK_b_SWAP").join(r);
}
//test 1
var str = 'this is "test" of a \'test\' of swapping strings';
var manipulated = swap_str(str,"'",'"');
document.writeln(manipulated)
//test 2
manipulated = swap_str(manipulated,"'",'"');
document.writeln('<hr>'+manipulated)

Emacs cond, possible to have things happen between clauses?

I programmed some months ago some code with a lot of if statements. If region-active-p, if beginning-of-line, those kind of things.
Having learned about the cond lisp, I was wondering if I could improve my code a lot.
The problem is that this cond is only doing things when "true" as far as I see it, while I actually need the move back-to-indentation in between these checks.
In order to properly skip the last clause, I even have to set variable values.
(defun uncomment-mode-specific ()
"Uncomment region OR uncomment beginning of line comment OR uncomment end"
(interactive)
(let ((scvar 0) (scskipvar 0))
(save-excursion
(if (region-active-p)
(progn (uncomment-region (region-beginning) (region-end))
(setq scskipvar 1))
(back-to-indentation)) ; this is that "else" part that doesn't fit in cond
(while (string= (byte-to-string (following-char)) comment-start)
(delete-char 1)
(setq scskipvar 1))
(indent-for-tab-command)
(when (= scskipvar 0)
(search-forward comment-start nil t)
(backward-char 1)
(kill-line))
)))
)
So basically my question is, I would kind of like to have some consequences of not giving "true" to a clause, before the check of another clause. Is this possible? If not, what would be the best thing to do?
EDIT: Since we are using this as the example case for a solution, I wrote it down so it is easier to understand.
If region is active, remove comments from region. If not, move point to intendation.
For as long as the following character is a comment character, delete it. Afterwards, indent this line.
If it didn't do any of the above, search forward for a comment character, and kill that line.
(defun delete-on-this-line (regex)
(replace-regexp regex "" nil (line-beginning-position) (line-end-position)))
(defun delete-leading-comment-chars ()
(delete-on-this-line (eval `(rx bol (* space) (group (+ ,comment-start))))))
(defun delete-trailing-comment-chars ()
(delete-on-this-line (eval `(rx (group (+ ,comment-end)) (* space) eol))))
(defun delete-trailing-comment ()
(delete-on-this-line (eval `(rx (group (+ ,comment-start) (* anything) eol)))))
(defun uncomment-dwim ()
(interactive)
(save-excursion
(if (region-active-p)
(uncomment-region (region-beginning) (region-end))
(or (delete-leading-comment-chars)
(delete-trailing-comment-chars)
(delete-trailing-comment)))))
Edit: A little explanation:
It's a lot easier to do regex replacements than manage loops to do deletion, so that gets rid of the state. And the steps are all mutually exclusive, so you can just use or for each option.
The rx macro is a little DSL that compiles down to valid regexes, and it's also amenable to lispy syntax transforms, so I can dynamically build a regex using the comment chars for the current mode.
(defmacro fcond (&rest body)
(labels ((%substitute-last-or-fail
(new old seq)
(loop for elt on seq
nconc
(if (eql (car elt) old)
(when (cdr elt)
(error "`%S' must be the last experssion in the clause"
(car elt)))
(list new)
(list (car elt))))))
(loop with matched = (gensym)
with catcher = (gensym)
for (head . rest) in body
collect
`(when (or ,head ,matched)
(setq ,matched t)
,#(%substitute-last-or-fail `(throw ',catcher nil) 'return rest))
into clauses
finally
(return `(let (,matched) (catch ',catcher ,#clauses))))))
(macroexpand '(fcond
((= 1 2) (message "1 = 2"))
((= 1 1) (message "1 = 1"))
((= 1 3) (message "1 = 3") return)
((= 1 4) (message "1 = 4"))))
(let (G36434)
(catch (quote G36435)
(when (or (= 1 2) G36434)
(setq G36434 t)
(message "1 = 2"))
(when (or (= 1 1) G36434)
(setq G36434 t)
(message "1 = 1"))
(when (or (= 1 3) G36434)
(setq G36434 t)
(message "1 = 3")
(throw (quote G36435) nil))
(when (or (= 1 4) G36434)
(setq G36434 t)
(message "1 = 4"))))
Here's something quick to do, what I think you may be after, i.e. something that would mimic the behaviour switch in C.
The idea is that all clauses are tested sequentially for equality, and if one matches, then all following clauses are executed, until the return keyword (it would be break in C, but Lisp uses return for the similar purpose in the loop, so I thought that return would be better). The code above thus will print:
1 = 1
1 = 3
Technically, this is not how switch works in C, but it will produce the same effect.
One thing I did here for simplicity, which you want to avoid / solve differently - the use of return keyword, you probably want to impose stricter rules on how it should be searched for.
cond
Cond evaluates a series of conditions in a list, each item in a list can be a condition, and then executable instructions.
The example in the Emacs Lisp manual is adequate to demonstrate how it works, I've annotated it here to help you understand how it works.
(cond ((numberp x) x) ;; is x a number? return x
((stringp x) x) ;; is x a string? return x
((bufferp x) ;; is x a buffer?
(setq temporary-hack x) ;; set temporary-hack to buffer x
(buffer-name x)) ;; return the buffer-name for buffer x
((symbolp x) (symbol-value x))) ;; is x a symbol? return the value of x
Each part of the condition can be evaluated any way you like, the fact x above is in each condition is coincidental.
For example:
(cond ((eq 1 2) "Omg equality borked!") ;; Will never be true
(t "default")) ;; always true
So comparisons with switch are a bit limited, it's essentially a list of if statements, that executes/returns the first true condition's body list.
Hopefully this helps you understand cond a bit better.
(cond (condition body ... ) ;; execute body of 1st passing
(condition body ... ) ;; condition and return result
(condition body ... ) ;; of the final evaluation.
;; etc
)
OR
You can do things similar to switch with OR, depending on how you structure the code.
This isn't functional style, because it relies on side-effects to do what you want, then returns a boolean value for flow control, here's an example in pseudo lisp.
(or)
(or
(lambda() (do something)
(evaluate t or nil) ; nil to continue; t to quit.
)
(lambda() (do something)
(evaluate t or nil) ; nil to continue; t to quit.
)
(lambda() (do something)
(evaluate t or nil) ; nil to continue; t to quit.
)
(lambda() (do something)
(evaluate t or nil) ; nil to continue; t to quit.
)
)
Here's working example of a switch like structure using or
(or
(when (= 1 1)
(progn
(insert "hello\n")
nil))
(when (= 1 2) ;; condition fails.
(progn
(insert "hello\n")
nil)) ;; returns false (nil)
(when (= 1 1)
(progn
(insert "hello\n")
t)) ;; returns true, so we bail.
(when (= 1 1)
(progn
(insert "hello\n")
nil))
)
Inserts :
hello
hello
(and)
The and operator (not just in Lisp) is also very useful, instead of evaluating everything until true, it evaluates conditions that are true, until a false is evaluated.
Both or & and can be used to build useful logic trees.
This is how I did it now according to Chris' idea that breaking it down into seperate functions would make it easier.
EDIT: Now also applied the or knowledge gained in this thread gained from Slomojo (no more variables!)
(defun sc-uncomment ()
(interactive)
(or
(if (region-active-p)
(uncomment-region (region-beginning) (region-end))
(back-to-indentation)
nil)
(if (string= (byte-to-string (following-char)) comment-start)
(sc-check-start)
(sc-end))))
(defun sc-check-start ()
(interactive)
(while (string= (byte-to-string (following-char)) comment-start)
(delete-char 1))
)
(defun sc-end ()
(interactive)
(search-forward comment-start nil t)
(backward-char 1)
(kill-line))
)

emacs query-replace-regexp inverted

Is there an existing package that targets subexps for replacement during
query-replace-regexp?
For example given the following
var foo1 = blah( properties, property_id);
var foo2 = blah(properties, property_id );
var foo3 = blah( properties, property_id );
I want to remove the padding around braces.
Normally, the way is to subgroup the bits you want to keep and assemble a replacement.
search:
\(var .* = blah\s-*(\)\s-*\(.*?\)\s-*\()\)
replace:
\1\2\3
However, it seems much easier to some up with a regexp that groups the bits I
want to delete than the otherway around. Like this one:
var .* = blah\s-*(\(\s-*\).*?\(\s-*\))
I'll get two subgroups out of this. How can I target them for replacement?
EDIT: I'm asking for an interactive way to "invert" the given regexp. So the interface would be similar to query-replace-regexp
enter regexp
enter replacement for group 1
enter replacement for group 2
I think some variation of this should work:
(defun remove-padding ()
(interactive)
(while (search-forward-regexp
"var .* = [a-zA-Z_]+\\s-*(\\(\\s-*\\).*?\\(\\s-*\\))"
nil t)
;; Replace the 2 subexpressions with nothing
(replace-match "" nil t nil 2)
(replace-match "" nil t nil 1)))
However, you might also consider using a tool like indent depending on what your use cases are.
EDIT: Below is a very minimal interactive version. The function query-replace-regexp is very complex and I have made no attempt to reproduce all of it's functionality.
(require 're-builder)
(defun query-replace-subexpressions (regexp replacements)
"REPLACEMENTS need to be in reverse order if passed from lisp!"
;; Read the correct number of subexpressions
(interactive
(let* ((re (read-from-minibuffer "Query replace subexps: "))
(num-subexps (reb-count-subexps re))
(replacement-list nil)
(replacements (dotimes (rep num-subexps)
(setq replacement-list
(cons
(read-from-minibuffer
(format "Replace subexpression %s with: " rep))
replacement-list)))))
(list re replacement-list)))
;; Search
(let ((len (length replacements)))
(while (search-forward-regexp regexp nil t)
(replace-highlight (match-beginning 0) (match-end 0)
(point-min) (point-max) regexp
t case-fold-search)
;; Query
(when (save-match-data (y-or-n-p "Replace this occurrence? "))
;; Make all the replacements
(dotimes (i len)
(replace-match (nth i replacements) nil nil nil (- len i)))))
(replace-dehighlight)))
;; Test it out below
(query-replace-subexpressions
"var .* = [a-zA-Z_]+\\s-*(\\(\\s-*\\).*?\\(\\s-*\\))"
'("" ""))
var foo1 = blah(properties, property_id );
var foo2 = blah (properties, property_id );
var foo3 = blah( properties, property_id );
I've made it hooking into query-replace-regexp on github
Here is a paste in case of link rot:
;; -*- lexical-binding: t -*-
(provide inverted-replace)
(require 're-builder)
(require 'parallel-replace)
(defun inverted-replace-generate-replacement (from to)
"invert result of current match (match-string 0)"
(let ((string (match-string 0))
(count (reb-count-subexps from))
(replacements (parallel-replace-read-list to)))
(save-match-data
(string-match from string)
(dotimes (i count)
(setq string (replace-match (nth i replacements) nil nil string (- count i)))))
string))
(defun inverted-replace-regexp (from to)
(interactive (destructuring-bind (from to _)
(query-replace-read-args "inverted-replace-regexp: " t)
(list from to)))
(query-replace-regexp from
(quote (replace-eval-replacement
replace-quote
(inverted-replace-generate-replacement from to)))
nil (and (and transient-mark-mode mark-active)
(region-beginning))
(and (and transient-mark-mode mark-active) (region-end))))

In elisp, how to evaluate a string of "var=value\n..." into lisp variables of the same name?

An mplayer tool (midentify) outputs "shell-ready" lines intended to be evaluated by a bash/sh/whatever interpreter.
How can I assign these var-names to their corresponding values as elisp var-names in emacs?
The data is in a string (via shell-command-to-string)
Here is the data
ID_AUDIO_ID=0
ID_FILENAME=/home/axiom/abc.wav
ID_DEMUXER=audio
ID_AUDIO_FORMAT=1
ID_AUDIO_BITRATE=512000
ID_AUDIO_RATE=0
ID_AUDIO_NCH=1
ID_LENGTH=3207.00
ID_SEEKABLE=1
ID_CHAPTERS=0
ID_AUDIO_BITRATE=512000
ID_AUDIO_RATE=32000
ID_AUDIO_NCH=1
ID_AUDIO_CODEC=pcm
ID_EXIT=EOF
Here's a routine that takes a string containing midentify output, and returns an association list of the key-value pairs (which is safer than setting Emacs variables willy-nilly). It also has the advantage that it parses numeric values into actual numbers:
(require 'cl) ; for "loop"
(defun midentify-output-to-alist (str)
(setq str (replace-regexp-in-string "\n+" "\n" str))
(setq str (replace-regexp-in-string "\n+\\'" "" str))
(loop for index = 0 then (match-end 0)
while (string-match "^\\(?:\\([A-Z_]+\\)=\\(?:\\([0-9]+\\(?:\\.[0-9]+\\)?\\)\\|\\(.*\\)\\)\\|\\(.*\\)\\)\n?" str index)
if (match-string 4 str)
do (error "Invalid line: %s" (match-string 4 str))
collect (cons (match-string 1 str)
(if (match-string 2 str)
(string-to-number (match-string 2 str))
(match-string 3 str)))))
You'd use this function like so:
(setq alist (midentify-output-to-alist my-output))
(if (assoc "ID_LENGTH" alist)
(setq id-length (cdr (assoc "ID_LENGTH" alist)))
(error "Didn't find an ID_LENGTH!"))
EDIT: Modified function to handle blank lines and trailing newlines correctly.
The regexp is indeed a beast; Emacs regexps are not known for their easiness on the eyes. To break it down a bit:
The outermost pattern is ^(?:valid-line)|(.*). It tries to match a valid line, or else matches the entire line (the .*) in match-group 4. If (match-group 4 str) is not nil, that indicates that an invalid line was encountered, and an error is raised.
valid-line is (word)=(?:(number)|(.*)). If this matches, then the name part of the name-value pair is in match-string 1, and if the rest of the line matches a number, then the number is in match-string 2, otherwise the entire rest of the line is in match-string 3.
There's probably a better way but this should do it:
(require 'cl)
(let ((s "ID_AUDIO_ID=0
ID_FILENAME=/home/axiom/abc.wav
ID_DEMUXER=audio
ID_AUDIO_FORMAT=1
ID_AUDIO_BITRATE=512000
ID_AUDIO_RATE=0
ID_AUDIO_NCH=1
ID_LENGTH=3207.00
ID_SEEKABLE=1
ID_CHAPTERS=0
ID_AUDIO_BITRATE=512000
ID_AUDIO_RATE=32000
ID_AUDIO_NCH=1
ID_AUDIO_CODEC=pcm
ID_EXIT=EOF"))
(loop for p in (split-string s "\n")
do
(let* ((elements (split-string p "="))
(key (elt elements 0))
(value (elt elements 1)))
(set (intern key) value))))
Here's a function you can run on the output buffer:
(defun set-variables-from-shell-assignments ()
(goto-char (point-min))
(while (< (point) (point-max))
(and (looking-at "\\([A-Z_]+\\)=\\(.*\\)$")
(set (intern (match-string 1)) (match-string 2)))
(forward-line 1)))
I don't think regexp is what really need. You need to split your string by \n and =, so you just say exactly the same to interpreter.
I think you can also use intern to get symbol from string(and set variables). I use it for the first time, so comment here if i am wrong. Anyways, if list is what you want, just remove top-level mapcar.
(defun set=(str)
(mapcar (lambda(arg)
(set
(intern (car arg))
(cadr arg)))
(mapcar (lambda(arg)
(split-string arg "=" t))
(split-string
str
"\n" t))))
(set=
"ID_AUDIO_ID=0
ID_FILENAME=/home/axiom/abc.wav
ID_DEMUXER=audio
ID_AUDIO_FORMAT=1
ID_AUDIO_BITRATE=512000
ID_AUDIO_RATE=0
ID_AUDIO_NCH=1
ID_LENGTH=3207.00
ID_SEEKABLE=1
ID_CHAPTERS=0
ID_AUDIO_BITRATE=512000
ID_AUDIO_RATE=32000
ID_AUDIO_NCH=1
ID_AUDIO_CODEC=pcm
ID_EXIT=EOF")