I'd like to search for regular expressions within a c/c++ buffer, but I want to avoid expression matching a comment region. Is there a way using the c mode to know if a bunch of text is within a comment region (or a point is within a comment region)?
The way to figure that out is with syntax-ppss which works in C/C++ and most major modes. E.g. (null (nth 8 (syntax-ppss))) will be non-nil if and only if you're not within a string-or-comment.
(defun re-search-forward-not-in-comment (regexp)
"Search forward first regexp not inside a comment. "
(interactive
(list (read-from-minibuffer "Regexp: ")))
(while (and (re-search-forward regexp nil t 1)
(and (nth 8 (syntax-ppss))(nth 4 (syntax-ppss))))))
Related
Premises:
My Emacs has a small bug (cannot go up from inside of "") in one of its original defun (up-list). This defun is vital to one of my frequently used command (backward-up-list) which is bound to C-M-u.
Therefore, I wanted to achieve below objectives:
Write a NEW defun named my-up-list which has the bug fix;
RE-write the native defun backward-up-list to call the above new defun (instead of the native buggy up-list). (By RE-writing under the same defun name, I intend to preserve its original convenient key bindings.)
By following the Emacs Tutorial Here, I implemented it as below:
I wrote a new defun my-up-list inside .emacs file; (see code in the end)
I rewrote the defun backward-up-list under a the same name inside .emacs file; (see code in the end).
However, when wI tested it out by trying it in "|" (| is the cursor position), I encounter below error:
backward-up-list: Wrong number of arguments: (lambda nil (interactive) (let ((s (syntax-ppss))) (if (nth 3 s) (progn (goto-char (nth 8 s))))) (condition-case nil (progn (up-list)) (error nil))), 1 [2 times]
Question:
Is it the correct way to re-write a native defun just by putting the
new implementation with the same name in .emacs file?
What may went wrong in my code?
Reference:
(The my-up-list is from here)
;; I only changed "up-list" to "my-up-list" -modeller
(defun backward-up-list (&optional arg)
"Move backward out of one level of parentheses.
With ARG, do this that many times.
A negative argument means move forward but still to a less deep spot.
This command assumes point is not in a string or comment."
(interactive "^p")
(my-up-list (- (or arg 1))))
;; copied from solution to another question - modeller
(defun my-up-list ()
(interactive)
(let ((s (syntax-ppss)))
(when (nth 3 s)
(goto-char (nth 8 s))))
(ignore-errors (up-list)))
I guess your my-up-list function needs to accept the same arguments as the original up-list, and call up-list with them?
The simplest way to do this is with the "advice" system. This provides some simple ways to wrap and extend existing functions. There's a whole section in the elisp manual explaining how to do it.
I want the sequence // to start a comment when it is at the beginning of a line. But inside of a line it should not start any comments.
// this is a comment
This is a URL: http://example.com
Is it possible?
I'd do it this way:
(defvar my-foo-mode-syntax-table
(let ((st (make-syntax-table)))
;; Add other entries appropriate for my-foo-mode.
(modify-syntax-entry ?/ ". 12" st)
(modify-syntax-entry ?\n "> " st)
st))
(defvar my-foo-font-lock-keywords
;; Add other rules appropriate for my-foo-mode.
())
(define-derived-mode my-foo-mode nil "My-Foo"
(setq-local font-lock-keywords '(my-foo-font-lock-keywords))
;; Add other settings appropriate for my-foo-mode.
(setq-local syntax-propertize-function
(syntax-propertize-rules ("./\\(/+\\)" (1 ".")))))
Notice: No need for any special font-lock rule since font-lock automatically highlights comments for you, based on the syntax-tables.
You can do this by writing a syntax-propertize-function
I have written an example major mode that shows this below.
Emacs built in parsing will call your syntax-propertize-function so that it can manually set the syntax-table text property on lines starting with //.
(define-derived-mode my-syntax-test-mode fundamental-mode
"A major mode where // denotes a comment but only if it is at the beginning of a line."
:syntax-table (make-syntax-table)
(setq mode-name "my syntax test")
;; our mode will use `apply-my-custom-syntax-table-appropriately' to manually set
;; the syntax-table text property on lines starting with //"
(setq syntax-propertize-function 'apply-my-custom-syntax-table-appropriately)
;; change `comment-dwim` to handle this type of comments correctly
(local-set-key [remap comment-dwim] 'my-comment-dwim))
(defvar my-custom-syntax-table
;; syntax table where // starts a comment and \n ends it
(let ((table (make-syntax-table)))
(modify-syntax-entry ?/ "< 1" table)
(modify-syntax-entry ?/ "< 2" table)
(modify-syntax-entry ?\n "> " table)
table))
(defun apply-my-custom-syntax-table-appropriately (beg end)
(save-excursion
(save-restriction
(widen)
(goto-char beg)
;; for every line between points BEG and END
(while (and (not (eobp)) (< (point) end))
(beginning-of-line)
;; if it starts with a //
(when (looking-at "^//")
;; remove current syntax-table property
(remove-text-properties (1- (line-beginning-position))
(1+ (line-end-position))
'(syntax-table))
;; set syntax-table property to our custom one
;; for the whole line including the beginning and ending newlines
(add-text-properties (1- (line-beginning-position))
(1+ (line-end-position))
(list 'syntax-table my-custom-syntax-table)))
(forward-line 1)))))
(defun my-comment-dwim (arg)
(interactive "*P")
(require 'newcomment)
(save-excursion
(let ((comment-start "//") (comment-end "")
(comment-column 0)
;; don't indent comments
(comment-style 'plain))
;; create the region containing current line if there is no active region
(unless (use-region-p)
(end-of-line)
(push-mark (line-beginning-position))
(setq mark-active t))
(comment-dwim nil))))
Answer: Use regexps
Short and simple
(define-derived-mode my-foo-mode prog-mode "My-Foo"
(setq-local font-lock-keywords t)
(setq-local syntax-propertize-function
(syntax-propertize-rules
((rx line-start (* whitespace) (group "//")) (1 "<"))
((rx (group "\n")) (1 ">")))))
That is all you need, but read on if you'd like to know more.
Explanation
This is based on #stefan's excellent solution which uses syntax-propertize-function to add to a syntax-table. While simpler isn't always better, #stefan's answer does more than what the original question asked for, so I've created this answer for people who only need a small hint or who just want to modify an existing mode.
It turns out directly manipulating a syntax table is unnecessary since the function syntax-propertize-rules makes it easy to map from regular expressions to syntax classes. For example, the syntax class < means "start of comment" and > means "end of comment". (See the Emacs lisp manual.)
I set font-lock-keywords to t as that is the minimum needed to enable syntax highlighting. If you are editing an existing mode, it likely already sets that variable and will not need to be changed.
And, finally, I use Emacs' rx function because it makes regular expressions sane in Lisp. (If you like Lisp, regular expressions, and sanity, I highly recommend using rx.)
About syntax-propertize-rules
I was going to link to the documentation for syntax-propertize-rules, but the Emacs manual does not (as of Emacs 28.1) even mention it. Until that gets remedied, I'll paste here the builtin documentation from C-hf:
syntax-propertize-rules is a Lisp macro in ‘syntax.el’.
(syntax-propertize-rules &rest RULES)
Probably introduced at or before Emacs version 24.1.
Make a function that applies RULES for use in
‘syntax-propertize-function’. The function will scan the buffer,
applying the rules where they match. The buffer is scanned a single
time, like "lex" would, rather than once per rule.
Each RULE can be a symbol, in which case that symbol’s value should
be, at macro-expansion time, a precompiled set of rules, as returned
by ‘syntax-propertize-precompile-rules’.
Otherwise, RULE should have the form (REGEXP HIGHLIGHT1 ...
HIGHLIGHTn), where REGEXP is an expression (evaluated at time of
macro-expansion) that returns a regexp, and where HIGHLIGHTs have the
form (NUMBER SYNTAX) which means to apply the property SYNTAX to the
chars matched by the subgroup NUMBER of the regular expression, if
NUMBER did match. SYNTAX is an expression that returns a value to
apply as ‘syntax-table’ property. Some expressions are handled
specially:
if SYNTAX is a string, then it is converted with ‘string-to-syntax’;
if SYNTAX has the form (prog1 EXP . EXPS) then the value returned by EXP will be applied to the buffer before running EXPS and if EXP is
a string it is also converted with ‘string-to-syntax’. The SYNTAX
expression is responsible to save the ‘match-data’ if needed for
subsequent HIGHLIGHTs. Also SYNTAX is free to move point, in which
case RULES may not be applied to some parts of the text or may be
applied several times to other parts.
Note: back-references in REGEXPs do not work.
My question builds on this answer by Trey Jackson to this question from SyntaxT3rr0r.
Trey proposes the following function for incrementing each two-digit number in the selected region of an Emacs buffer.
(defun add-1-to-2-digits (b e)
"add 1 to every 2 digit number in the region"
(interactive "r")
(goto-char b)
(while (re-search-forward "\\b[0-9][0-9]\\b" e t)
(replace-match (number-to-string (+ 1 (string-to-int (match-string 0)))))))
I would like to use this function for my own purposes. However, I would like to increment the numbers many times successively. The problem with the function, in its current form, is that before each invocation, I have to select the region again with my mouse.
My question is: How can Trey's function be modified so that it leaves the region selected after invocation? (My ultimate aim is to assign this function to a keyboard shortcut (something like ctrl+↑) so that I if I keep the ctrl and ↑ keys held down, all the two-digit numbers in my selected region will continuously increase.)
By the way, I am aware of this answer by Brian Campbell, which suggests using exchange-point-and-mark to re-select a previously-selected region. However, I tried that, and it doesn't seem to help in this instance.
Here's your function modified to use let (deactivate-mark) wrapped inside save-excursion as suggested in the answer user event_jr linked to:
https://stackoverflow.com/a/11080667/903943
(defun add-1-to-2-digits (b e)
"add 1 to every 2 digit number in the region"
(interactive "r")
(save-excursion
(let (deactivate-mark)
(goto-char b)
(while (re-search-forward "\\b[0-9][0-9]\\b" e t)
(replace-match (number-to-string (+ 1 (string-to-int (match-string 0)))))))))
You need to bind deactivate-mark to prevent it from being set see:
https://stackoverflow.com/a/11080667/903943
manual: http://www.gnu.org/software/emacs/manual/html_node/elisp/The-Mark.html#index-deactivate_002dmark-2801
It seems that when vimpulse is running, autopair only works partially in the sense that pressing backspace in empty bracket pairs will no longer remove the closing bracket but only the opening one (which means backspace functions as normal backspace now). An example:
(When Vimpulse and autopair are both active, and current mode is INSERT mode, "|" denotes the cursor)
begin: (|)
Now press "backspace"
expected result: | (both opening and closing brackets are removed)
actual result: |) (only the opening bracket is removed)
I know this has to do with the fact that vimpulse (or rather viper-mode) remapped [backspace] from delete-backward-char to something else (viper-delete-backward-char I think). But I could not find a fix to it.
Could anybody find a solution to this? (so that backspace key will remove both opening and closing bracket when the bracket is empty and cursor is in between).
Thanks!
i think something like this in your init file would work:
(add-hook 'autopair-mode-hook
'(lambda ()
(define-key autopair-emulation-alist [remap viper-delete-backward-char] 'autopair-backspace)))
I will answer this question myself.
I could not figure out an "orthodoxy" way to solve the problem and I came up with a hack.
The function that is bound to in viper insert mode (viper-del-backward-char-in-insert) is adviced to check whether cursor is currently in a matched pair, if so, the character after the cursor is deleted before the actual function is called. This also takes into account possible problem caused by prefix character (backslash).
Just copy the code below into your .emacs file after viper-mode or vimpulse is loaded.
(defun not-escaped (escape-char)
"Character immediately before cursor is not prefixed by escape-char"
(let ((count 0))
(save-excursion
(if (char-before)
(backward-char))
(while (and (char-before)
(= (char-before) escape-char))
(setq count (+ count 1))
(backward-char))
(if (= 0
(% count 2))
t
nil))))
(defun in-matched-empty-pair (pair-list)
"tell if cursor is in an empty pair in pair-list"
(let ((next-char (char-after))
(prev-char (char-before))
(matched nil)
(pair)
(pair-left)
(pair-right))
(if (and next-char
prev-char)
(while (and (setq pair
(pop pair-list))
(not matched))
(setq pair-left (pop pair)
pair-right (pop pair))
(if (= next-char pair-right)
(if (and
(= prev-char pair-left)
(not-escaped ?\\))
(setq matched t)))))
(if matched
t
nil)))
(defvar viper-workaround-pairs
'(
(?\" ?\")
(?\' ?\')
(?\` ?\`)
(?\( ?\))
(?\[ ?\])
(?\{ ?\})
))
;; Workaround for integration problem with autopair
(defadvice viper-del-backward-char-in-insert (before viper-auto-delete-pair-backward())
(if (in-matched-empty-pair viper-workaround-pairs)
(delete-char 1)))
;; Activate advice
(ad-activate 'viper-del-backward-char-in-insert)
This is a hack but it is probably the best I could do now.
Here is my updated solution. Put the following in your .emacs file after the code that loads autopair and vimpulse:
(add-to-ordered-list 'emulation-mode-map-alists (car (last emulation-mode-map-alists)) 400)
It moves autopair's keymap in front of viper's one, giving it higher priority.
Maybe you have to adept the order number (here 400), depending on whether you are using additional emulation-modes.
The result can be checked with C-x v emulation-mode-map-alists. In my case:
(viper--intercept-key-maps cua--keymap-alist autopair-emulation-alist viper--key-maps)
Now, autopair-emulation-alist should be listed before viper--key-maps.
baumichel found the trick. I just add a quick snippet to help :
First, as autopair-mode simply appends autopair-emulation-alist, evaluate:
(defadvice viper-change-state-to-insert (after autopair nil activate)
(add-to-ordered-list 'emulation-mode-map-alists 'autopair-emulation-alist 300))
Then, remember that vimpulse-normalize-minor-mode-map-alist removes all viper keymaps in front of the alist, so execute:
(defadvice vimpulse-normalize-minor-mode-map-alist (after order-viper--key-maps nil activate)
(add-to-ordered-list 'emulation-mode-map-alists 'viper--key-maps 500))
That works for me! I evaluate these snippets in an embedded eval-after-load for both vimpulse and autopair.
My idea is that Emacs dev should rethink the emulation-mode-map-alists and use a property list indexing priority order like this: ((:name viper--key-maps :after (cua--keymap-alist autopair-emulation-alist)) (:name viper--intercept-key-maps :before (cua--keymap-alist autopair-emulation-alist))). Old packages like viper, CUA and so on should be better maintained because our setup becomes ugly after years with Emacs.
suppose I have a text list in emacs like this:
a
b
c
...
d
Is there a way to assign numbers to those items in Emacs, by selecting the region? End results should look like:
1. a
2. b
3. c
j. ...
n. d
Thanks.
The way I do this, which may not be optimal, is to use regex search and replace. This, of course, requires that you be able to define a regex to match the start of the lines you want numbers on. Taking your example, I'd use a search regex like this:
\([a-z]\)
note the capturing brackets, we'll need that first letter soon. And a replace regex like this:
\#. \1
where:
\# is a special form which is replaced, by Emacs, by the right number (though see the warning below);
. writes a stop; and
\1 writes a space and the captured group.
WARNING: Emacs will number your items 0, 1, 2, .... Until someone posts to tell us how to start at 1, I always insert a dummy 0th element before the edit, then delete it.
You can use the Emacs Keyboard Macro Counter.
Put the cursor one line ABOVE your list.
Start a macro: F3
Insert the counter value: C-x C-k C-i. A 0 will appear
Insert the DOT and a space: .
Move the cursor to the next line
Stop the macro: F4
Select your list
M-x apply-macro-to-region-lines
You can delete the 0 you added on the top and enjoy :)
NOTE: This will create a numbered list. It will not use letters.
A much simpler way is to use the CUA library's advanced rectangle editing commands. CUA is included in Emacs (at least 23.1, I think it's in earlier versions as well), so there isn't any new code to get.
You can use cua-set-rectangle-mark (bound to C-Return by default) to start a rectangle, and then use cua-sequence-rectangle to insert increasing values. It also gives you control over the format and starting value, so there is a lot of flexibility.
As an aside, CUA is primarily designed to make Emacs operate more like standard text editors (with C-c for copy, C-v for paste, etc), but it also includes some unrelated niceties, like rectangle editing. Don't ask me why :). If you want to use the rectangle editing without enabling the CUA keybindings (which is what I do), set cua-enable-cua-keys to nil, which can be done via customize.
(defun number-region (start end)
(interactive "r")
(let* ((count 1)
(indent-region-function (lambda (start end)
(save-excursion
(setq end (copy-marker end))
(goto-char start)
(while (< (point) end)
(or (and (bolp) (eolp))
(insert (format "%d. " count))
(setq count (1+ count)))
(forward-line 1))
(move-marker end nil)))))
(indent-region start end)))
Here's some elisp code to do it; would be easy to customize if you like tinkering.
This will number the current region (unless it is already numbered), and also the last line binds to the M-n keys. You could use a function key "[F6]" as needed.
Modified to take a format string to use. The default is 1. but you could do something like %d) to get a bracket instead of a . and so on.
(defun number-region(fmt)
(interactive "sFormat : ")
(if (or (null fmt) (= 0 (length fmt)))
(setf fmt "%d. "))
(save-excursion
(save-restriction
(narrow-to-region (point) (mark))
(goto-char (point-min))
(let ((num 1))
(while (> (point-max) (point))
(if (null (number-at-point))
(insert (format fmt num)))
(incf num)
(forward-line))))))
(global-set-key "\M-n" 'number-region)
Not a direct answer to your question, but if you find yourself manipulating numbered lists frequently, you may want to look into org-mode. In particular, the section on plain lists.