macro for making a template - emacs

I am new to emacs and trying to figure out if there is an "easy" way to write a macro that will create a template for a standard function specification (see lines with # below). For example, I would like to execute a command to extract the input and output variables and place them in this standard format above the function (using the R language):
#This function does something
#Input:
# var1 - h
# var2 -
# var3 -
# var4 -
# Output:
# myoutput -
MyFunction <- function(var1,var2,var3=13,var4=NULL){
...
...
return(myoutput)
}

I don't know R so I'm just guessing how it looks from your one example. Add this to your Emacs init file (and evaluate it or restart), go to a function definition line and M-x my-r-insert-function-template:
(defun my-r-insert-function-template ()
"Insert a function template."
(interactive)
(let (name inputs output pos)
(beginning-of-line)
(save-excursion
(when (re-search-forward "\\([a-zA-Z0-9_\\.]+\\)\\s-*<-\\s-*function\\s-*(" nil t)
(setq name (match-string-no-properties 1))
(backward-char)
(forward-sexp)
(setq pos (1- (point)))
(backward-sexp)
(while (re-search-forward "[a-zA-Z0-9_\\.]+" pos 'go)
(push (match-string-no-properties 0) inputs)
(search-forward "," pos 'go))
(search-forward "{")
(setq pos (point))
(backward-char)
(forward-sexp)
(when (re-search-backward "return\\s-*(\\s-*\\([a-zA-Z0-9\\.]+\\)" pos t)
(setq output (match-string-no-properties 1)))))
(when name
(insert "# " name " : This function does something\n")
(when inputs
(insert "# Input:\n")
(setq inputs (nreverse inputs))
(dolist (input inputs)
(insert "# " input " -\n")))
(when output
(insert "# Output:\n")
(insert "# " output " -\n")))))

I don't use R but it looks like ESSr-autoyas could be used to do what you want. It makes use of YASnippet (a template package for Emacs).

Related

elisp implementation of the "uniq -c" Unix command to count unique lines

If there is a data in region:
flower
park
flower
stone
flower
stone
stone
flower
M-x some-command should give me in different buffer:
4 flower
2 stone
1 park
This data can then be sorted by frequency or item.
I suppose a common method would be to just hash the strings and then print the contents. This approach can be easily accomplished in emacs.
;; See the emacs manual for creating a hash table test
;; https://www.gnu.org/software/emacs/manual/html_node/elisp/Defining-Hash.html
(defun case-fold-string= (a b)
(eq t (compare-strings a nil nil b nil nil t)))
(defun case-fold-string-hash (a)
(sxhash (upcase a)))
(define-hash-table-test 'case-fold
'case-fold-string= 'case-fold-string-hash)
(defun uniq (beg end)
"Print counts of strings in region."
(interactive "r")
(let ((h (make-hash-table :test 'case-fold))
(lst (split-string (buffer-substring-no-properties beg end) "\n"
'omit-nulls " "))
(output-func (if current-prefix-arg 'insert 'princ)))
(dolist (str lst)
(puthash str (1+ (gethash str h 0)) h))
(maphash (lambda (key val)
(apply output-func (list (format "%d: %s\n" val key))))
h)))
Output when selecting that text
4: flower
1: park
3: stone
I suppose there are lots of approaches you could take to this. Here's a fairly simple approach:
(defun uniq-c (beginning end)
"Like M-| uniq -c"
(interactive "r")
(let ((source (current-buffer))
(dest (generate-new-buffer "*uniq-c*"))
(case-fold-search nil))
(set-buffer dest)
(insert-buffer-substring source beginning end)
(goto-char (point-min))
(while (let* ((line (buffer-substring (line-beginning-position)
(line-end-position)))
(pattern (concat "^" (regexp-quote line) "$"))
(count (count-matches pattern (point) (point-max))))
(insert (format "%d " count))
(forward-line 1)
(flush-lines pattern)
(not (eobp))))
(pop-to-buffer dest)))
It is similar to uniq -c in bash.
Then why not use uniq -c?
With the region highlighted, M-| "sort | uniq -c", will run that command on the current region. The results will show in the minibuffer and will be listed in *Messages* buffer. Adding a prefix arg will insert the results into the current buffer.

Removing enclosed text in Emacs

I would like to delete enclosed text between special characters like: ["{'<( etc .. this way I can remove text like "this is a very ... long text" with a simple keyboard shortcut. I was looking for some already existing mode that performs something similar but I didn't found any so I created some lisp code which performs good in most of situations, however it's not working correctly in all cases. For example if I have the following text entry and I put the cursor in the position"^" then I would liek to remove all the text enclosed by " but it doesn't work:
"aaaaa ] > [more text] aaaaa"
------------ ^
My lisp code is the following:
;; returns the enclosing character for the character "c"
(defun get-enc-char (c) (cond
((string= c "(") ")")
((string= c "[") "]")
((string= c "{") "}")
((string= c ">") "<")
((string= c "<") ">")
((string= c "'") "'")
((string= c "\"") "\"")
(t nil)
)
)
(defun delete-enclosed-text ()
"Delete texts between any pair of delimiters."
(interactive)
(save-excursion
(let (p1 p2 mychar)
; look for one of those characters and store the cursor position
(skip-chars-backward "^([\'\"><{") (setq p1 (point))
; store the char at this point, look for its enclosed char and advance
; the cursor newly (this done to avoid the cases when the char and
; its enclosed-char are the same like " or ' chars.
(backward-char 1) (setq mychar (thing-at-point 'char)) (forward-char 1)
; look forward for the enclosed char
(skip-chars-forward (concatenate 'string "^" (get-enc-char mychar))) (setq p2 (point))
; only delete the region if we found the enclosed character
(if (looking-at "[\]\}\"\'\)<>]") (kill-region p1 p2)))))
Following is an example:
Here a solution based on your code
;; returns the enclosing character for the character "c"
(defun get-enc-char (c) (cond
((string= c "(") ")")
((string= c "[") "]")
((string= c "{") "}")
((string= c ">") "<")
((string= c "<") ">")
((string= c "'") "'")
((string= c "\"") "\"")
(t nil)
))
(defvar empty-enclose 0)
(defun delete-enclosed-text ()
"Delete texts between any pair of delimiters."
(interactive)
(setq empty-enclose 0)
(save-excursion
(let (p1 p2 orig)
(setq orig (point))
(setq p1 (point))
(setq p2 (point))
(setq find 0)
(setq mychar (thing-at-point 'char))
(if (-contains? '("(" "[" "{" "<" "'" "\"") mychar)
(progn
(setq left_encloser (thing-at-point 'char))
(backward-char -1)
(if (string-equal (thing-at-point 'char) (get-enc-char left_encloser))
(progn
(backward-char -1)
(setq p2 (point))
(setq find 1)
(setq empty-enclose 1)))))
(while (eq find 0)
(skip-chars-backward "^({[<>\"'")
(setq p1 (point))
(backward-char 1)
(setq left_encloser (thing-at-point 'char))
(goto-char orig)
(while (and (not (eobp)) (eq find 0))
(backward-char -1)
(skip-chars-forward "^)}]<>\"'")
(setq right_encloser (thing-at-point 'char))
(if (string-equal right_encloser (get-enc-char left_encloser))
(progn
(setq p2 (point))
(setq find 1))))
(goto-char p1)
(backward-char 1))
(delete-region p1 p2)))
(if (eq empty-enclose 0)
(backward-char 1)))
I rapid-sketched something, it doesn't match exactly what you're asking for but I think it could fullfill the same requirements in an even more comfortable way, give it a try and let me know! This interactive function is called with no arguments after selecting a region and asks you for an enclosing mark: this can be any char or string that is directly recognized by replace-regex (direct use of *,.,[ etc wouldn't be the case, but you still can use other chars like {},% etc or even HTML-like markups like <idx>).
The function will delete all text within the selected region, from the very first apparition of the mark to the very last (even if there is an odd number of them), marks are also deleted.
(defun remove-enclosed-in-selection (beginning end)
"select a region, call this function and type any valid regex
markup. All characters from its first to its last appearance will
be removed (including the symbol itself. Example: try with § and %:
aaaa§bbbbcc%c§cc§ddddeeee§ffffgggghhhhiiii§jjjj§kkkkllll§mmmm%nnnn"
(interactive "r")
(let ((x (read-string "type enclosing mark: ")))
(narrow-to-region beginning end)
(replace-regexp (concat x ".*" x) "")
(widen)))
Then you can globally bind it to any keyboard shortcut you want as usual:
(global-set-key (kbd "C-. <C-return>") 'remove-enclosed-in-selection)
or locally to any custom hook you may have:
(defun custom-whatever-hook ()
(local-set-key (kbd "C-. <C-return>")) 'remove-enclosed-in-selection)
(add-hook 'whatever-hook 'custom-whatever-hook)
so, summarizing:
select region
M-x remove-enclosed-in-selection or your custom keystroke
press RET, type valid marker, press RET
the enclosed contents should be removed
The narrow-widen approach seems quick&dirty to me, but I couldn't find another way in the short term. So it may still need a couple of fixes, let me know if it works as expected. Plus, I'm not that an emacs hacker... yet! :P
cheers

Convert command line arguments to list in Emacs Lisp

In an automated Emacs Lisp --batch/--script script I need to process the command line arguments given to the script.
I've gotten as far as getting the arguments into a list of the the form:
("--aaa=bbb" "--ccc=ddd=eee" "--blah")
Now, I need to convert them to a list of the form:
(("aaa" "bbb") ("ccc" "ddd=eee") ("blah"))
In Python I'd write something like;
output = []
for v in input:
output.append(v[2:].split("=", 1))
But have been unable to convert that code to Emacs Lisp. I found Elisp split-string function to split a string by . character but wasn't able to figure out how to make it only split on the first equals.
I was heading down a route of using (substring "abcdefg" x x) with (search) from the cl package but it felt like there should be a better way? I think also want to use (mapc '<function> input) where function does the v[2:].split("=",1) part.
You can use split-string. See the following code example.
(setq cmd-line '("--aaa=bbb" "--ccc=ddd=eee" "--blah"))
(setq cmd-line (mapcar (lambda (argstr)
(when (string-match "^--" argstr)
(split-string (substring argstr 2) "=")))
cmd-line))
The output is (("aaa" "bbb") ("ccc" "ddd" "eee") ("blah")).
That is not exactly what you want because of "eee". Maybe you can use that and just neglect "eee".
If the "eee" is really a problem a small modification helps:
(setq cmd-line '("--aaa=bbb" "--ccc=ddd=eee" "--blah"))
(setq cmd-line (mapcar (lambda (arg)
(when (string-match "^--" arg)
(setq arg (split-string (substring arg 2) "="))
(if (cdr arg)
(setcdr (cdr arg) nil))
arg))
cmd-line))
The output is:
(("aaa" "bbb") ("ccc" "ddd") ("blah"))
Variant for the new requirement in the question:
(setq cmd-line '("--aaa=bbb" "--ccc=ddd=eee" "--blah"))
(setq cmd-line (mapcar (lambda (arg)
(when (string-match "^--\\([^=]*\\)\\(?:=\\(.*\\)\\)?" arg)
(let ((opt (match-string 1 arg))
(val (match-string 2 arg)))
(if val
(list opt val)
(list opt)))))
cmd-line))
The output is:
(("aaa" "bbb") ("ccc" "ddd=eee") ("blah"))

How to finish this job in emacs?

The original string is like this:
# chrom,name,strand,txStart
And the result should looks like this:
# $1: chrom
# $2: name
# $3: strand
# $4: txStart
Does anyone have idea of a quick way to do that?
Lots of ways.
You could use a search and replace making use of the \# counter in the replacement. That's zero-based, so you'd either need to add a dummy replacement at the front to use up the zero, or else use the elisp replacement expression \,(1+ \#) instead.
You could use a keyboard macro, and insert a counter with C-xC-kTAB or <f3>. You can seed that counter by supplying a prefix argument when you start recording.
On Emacs 24 you can number the lines of a marked region using a custom format string with C-uC-xrN, so your format string could be # $%1d:
Evaluate following code and execute foo function on input line.
(require 'cl)
(defun foo ()
(interactive)
(let* ((str (buffer-substring-no-properties
(line-beginning-position) (line-end-position)))
(words-str (and (string-match "# \\(.+\\)$" str)
(match-string 1 str)))
(buf (get-buffer-create "*tmp*")))
(unless words-str
(error "Line should be '# word1,word2,...'"))
(with-current-buffer buf
(erase-buffer)
(loop with index = 1
for word in (split-string words-str ",")
do
(progn
(insert (format "# $%d: %s\n" index word))
(incf index)))
(pop-to-buffer buf))))

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