I am trying to search forward in the current buffer for the first elisp function definition that is not a comment. I tried this:
(re-search-forward "[^;] *\(defun ")
but it matches comments anyway. Like the following line:
;; (defun test ()
You can use:
(catch 'found
(let (match)
(while (setq match (search-forward "(defun "))
(when (null (syntax-ppss-context (syntax-ppss)))
(throw 'found match)))
nil))
It relies on the internal parser and the language syntax definition. It returns only the result of search-forward if point is not in a comment and not in a string.
If you do not like the error in the case of a search without hits you can add nil t to the arguments of the search-forward command. Search with re-search-forward is also fine.
This also works for cases like:
(defun test (args)
"This function is defined with (defun test (args) ...)"
)
The space in (defun test () actually matches [^;]. Since you have *, another space is not needed. You may want to use [^;] +. However, you can use a negative lookbehind via
\(?<!;;)
This seems to work nicely for me (tested in *scratch*):
(re-search-forward "^ *\(defun " nil t) ; hit C-x C-e after that
; closing parenthesis
;; (defun hi () )
(defun hola () )
Related
I am working on cleaning files with multiple regex-replacement
<<.*>> -> ""
\([[:alpha:]]\)\* -> \1 ;; patters as pragram* to program
\*\([[:alpha:]]\) -> \1 ;; patters as *program to program
\*/\([[:alpha:]]\) -> \1
;;and so on
On every single file, I have to invoke replace-regexp various times.
How could combine these regex search?
To an extent, M-x whitespace-cleanup has similar requirements, that is, cleanup base on multiple conditions. It should be possible to use (emacs) Keyboard Macros, but I am not familiar with it. Once you have some knowledge in Emacs Lisp, you can solve the problem easily, for example, the following cleanups leading and trailing spaces, you can add your regexp and their replacement into my-cleanup-regexps:
(defvar my-cleanup-regexps
'(("^ +" "")
(" +$" ""))
"A list of (REGEXP TO-STRING).")
(defun my-cleanup-replace-regexp (regexp to-string)
"Replace REGEXP with TO-STRING in the whole buffer."
(goto-char (point-min))
(while (re-search-forward regexp nil t)
(replace-match to-string)))
(defun my-cleanup ()
"Cleanup the whole buffer according to `my-cleanup-regexps'."
(interactive)
(dolist (r my-cleanup-regexps)
(apply #'my-cleanup-replace-regexp r)))
I would like to have a hook into Emacs's isearch-forward function to make it automatically apply a regex between the input characters while searching a string. For example, I would like to set this regex to [-=<>]. If I now type foobar into isearch, it should match foo<bar, fo=ob=>ar, f-o-o-b-a-r, etc.
Is such a functionality already available? I looked into ELPA and MELPA without success. In case this is not available, and since my Elisp abilities are very limited: How could this be implemented?
OK, I found a solution by myself after inspecting hexl.el from Emacs.
Here's the code.
(defun my-isearch-function ()
"Make isearch skip characters -=<> while searching."
(if (not isearch-regexp)
(lambda (string &optional bound noerror count)
(funcall
(if isearch-forward
're-search-forward
're-search-backward)
(mapconcat (lambda (c) (regexp-quote (string c))) string
"\\(?:[-=<>]*\\)?")
bound
noerror
count))
(isearch-search-fun-default)))
(defun toggle-my-isearch ()
"Toggle my search mode.
If activated, incremental search skips characters -=<> while
searching.
For example, searching `foobar' matches `foo-bar' or `f-o-o=b<a>r'."
(interactive)
(if (eq isearch-search-fun-function 'isearch-search-fun-default)
(progn
(setq isearch-search-fun-function 'my-isearch-function)
(message "my isearch on"))
(setq isearch-search-fun-function 'isearch-search-fun-default)
(message "my isearch off")))
(global-set-key (kbd "s-s") 'toggle-my-isearch)
I wrote a package called flex-isearch, that basically inserts ".*" in between each character of the search string (it's a bit more complicated than that) and switches to regexp searching. It does this automatically when the isearch fails.
I don't understand how to re-use an interactive command in a command I'm writing myself.
I want to make a command that always uses the same arguments to replace-regexp. It's a shortcut, really.
So I tried to mimic in a function what I'd done interactively on a selected region, namely:
M-x replace-regexp RET ^\(\s *\)\(.*\)\s *$ RET \1 + '\2'
I mimicked it by writing this function:
(defun myH2js ()
"Converts html to an (incomplete) JavaScript String concatenation."
(interactive)
(let (p1 p2)
(setq p1 "^\(\s *\)\(.*\)\s *$" )
(setq p2 "\1 + '\2'" )
(replace-regexp p1 p2 )
)
)
But my function "replaces zero occurrences" of the selected region whereas my interaction rewrites everything exactly as I want.
What am I doing wrong?
You need to double the backslashes in the strings, because backslash is both the string and regular expression escape character:
(defun myH2js (start end)
"Converts html to an (incomplete) JavaScript String concatenation."
(interactive "r")
(let ((p1 "^\\(\\s *\\)\\(.*\\)\\s *$")
(p2 "\\1 + '\\2'"))
(replace-regexp p1 p2 nil start end)
)
)
Note that replace-regexp is not recommended for use inside programs; the online documentation says:
This function is usually the wrong thing to use in a Lisp program.
What you probably want is a loop like this:
(while (re-search-forward regexp nil t)
(replace-match to-string nil nil))
which will run faster and will not set the mark or print anything.
As a first experience in defining a function for emacs, I would like to make write a function that take all occurences of argv[some number] and renumber them in order.
This is done inside emacs with replace-regexp, entering as search/replace strings
argv\[\([0-9]+\)\]
argv[\,(+ 1 \#)]
Now, I want to write this in my .emacs so I understand I need to escape also for Lisp special characters. So in my opinion it should write
(defun argv-order ()
(interactive)
(goto-char 1)
(replace-regexp "argv\\[[0-9]+\\]" "argv[\\,\(+ 1 \\#\)]")
)
The search string works fine but the replacement string gives me the error "invalid use of \ in replacement text. I've been trying around adding or removing some \ but with no success.
Any idea ?
Quoting the help from replace-regexp (the bold is mine):
In interactive calls, the replacement text may contain `\,'
You are not using it interactively in your defun, hence the error message. Another quote from the same help that helps solving your problem:
This function is usually the wrong thing to use in a Lisp program.
What you probably want is a loop like this:
(while (re-search-forward REGEXP nil t)
(replace-match TO-STRING nil nil))
which will run faster and will not set the mark or print anything.
And a solution based on that:
(defun argv-order ()
(interactive)
(let ((count 0))
(while (re-search-forward "argv\\[[0-9]+\\]" nil t)
(replace-match (format "argv[%d]" count) nil nil)
(setq count (1+ count)))))
This is related to
Emacs: regular expression replacing to change case
My additional problem is that I need to script the search-replace but the "\,()" solution works (for me) only when used interactively (emacs 24.2.1). Inside a script it gives the error: "Invalid use of \' in replacement text".
I usually write a "perform-replace" to some file to be loaded when needed. Something like:
(perform-replace "<\\([^>]+\\)>" "<\\,(downcase \1)>" t t nil 1 nil (point-min) (point-max))
It should be possible to call a function to generate the replacement (pg 741 of the emacs lisp manual), but I've tried many variations of the following with no luck:
(defun myfun ()
(downcase (match-string 0)))
(perform-replace "..." (myfun . ()) t t nil)
Can anyone help?
Constructs like \,() are only allowed in interactive calls to query-replace, which is why Emacs complains in your case.
The documentation of perform-replace mentions that you should not use it in elisp code and proposes a better alternative, upon which we can build the following code:
(while (re-search-forward "<\\([^>]+\\)>" nil t)
(replace-match (downcase (match-string 0)) t nil))
If you still want to interactively query the user about the replacements, using perform-replace like you did is probably the right thing to do. There were a few different problems in your code:
As stated in the elisp manual the replacement function must take two arguments (the data you provide in the cons cell and the number of replacements already made).
As stated in the documentation of query-replace-regexp (or the elisp manual), you need to ensure that case-fold-search or case-replace is set to nil so that the case pattern is not transferred to the replacement.
You need to quote the cons cell (myfun . nil), otherwise it will be interpreted as a function call and evaluated too early.
Here is a working version:
(let ((case-fold-search nil))
(perform-replace "<\\([^>]+\\)>"
`(,(lambda (data count)
(downcase (match-string 0))))
t t nil))
C-h f perform-replace says:
Don't use this in your own program unless you want to query and set the mark
just as `query-replace' does. Instead, write a simple loop like this:
(while (re-search-forward "foo[ \t]+bar" nil t)
(replace-match "foobar"))
Now the "<\\,(downcase \1)>" needs to be replaced by an Elisp expression that builds the proper string, such as (format "<%s>" (downcase (match-string 1))).
If you do need the query and stuff, then you might like to try: C-M-% f\(o\)o RET bar \,(downcase \1) baz RET and then C-x RET RET to see what arguments were constructed during the interactive call.
You'll see discover (even better if you click on replace.el in C-h f perform-replace to see the source code of the function), that the replacements argument can take the form (FUNCTION . ARGUMENT). More specifically, the code includes a comment giving some details:
;; 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.