How to check whether the character before point equals "\"
(defun comment-latex ()
(interactive)
(if (region-active-p)
(comment-region (region-beginning) (region-end))
(if (= (char-before) ("\\") ;; how to fix this sentence?
(insert "%")
(if (= (point) (line-beginning-position)) ;; this part works
(insert "% ")
(end-of-line)
(insert " % "))))
)
(global-set-key LaTeX-mode-map (kbd "%") 'comment-latex)
The code as example should be doing the following:
1) If a region is selected, the region should be commented.
2) If the character before point is a "\", a normal % should be inserted at point.
3) If point is at the beginning of line, insert a "%"
4) If point is anywhere else, go to the end of the sentence and insert "SPC % SPC"
The syntax for individual characters is ?char. So:
(= (char-before) ?\\)
Replace it with
(= (char-before) 92)
92 is the ASCII code of the \ character.
In e-lisp, a character is not the same as a string. The syntax for getting the ascii value of a character is ?a. Try something like:
(if (= (char-before) ?\\))
DO-SOMETHING
DO-SOMETHING-ELSE)
Related
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
In programming we ofter have a task of selecting text between quotes. Suppose, we have the following PHP code:
lwt_shared_save_conditions_to_session($conditions, "bundles_listing"■);
The cursor position is shown with black square. And we want to select and copy the text "bundles_listing" into the clipboard. I created the following function:
(defun select-quoted-text ()
(interactive)
(search-backward "\"")
(forward-char 1)
(cua-set-mark)
(backward-char 1)
(search-backward "\"")
(kill-ring-save (region-beginning) (region-end))
)
It will select the text between quotes.
How can I do the following:
1.Fold this code into 1 function call:
(forward-char 1)
(cua-set-mark)
(backward-char 1)
Select text both between single ' and double " quotes.
Try this:
(defun copy-quoted ()
"Copy current string into kill-ring.
The point can be anywhere in the string."
(interactive)
(let ((beg (or (nth 8 (syntax-ppss))
(and (memq (char-after (point))
'(?\" ?\'))
(point))))
end)
(when beg
(setq end
(save-excursion
(goto-char beg)
(forward-sexp)
(point)))
(kill-ring-save beg end))))
Here's how I'd do it interactively (rather than defining a function for it):
C-SPC C-M-b M-w
That runs the following commands:
set-mark-command
backward-sexp
kill-ring-save
Quite often I need to capture some paragraphs in a region with regexp - and then act on each paragraph.
For example consider a problem of recovering a numberd list:
1. Some text with a blank
line. I want not to have that line break
2. Some more text. Also - with
a line break.
3. I want to have a defun which
will capture each numbered entry
and then join it
I want to write a defun which will make the previous text like that:
1. Some text with a blank line. I want not to have that line break
2. Some more text. Also - with a line break.
3. I want to have a defun which will capture each numbered entry and then join it
Here's my best try for now:
(defun joining-lines (start end)
(interactive "r")
(save-restriction
(narrow-to-region start end)
(goto-char (point-min))
(while (search-forward-regexp "\\([[:digit:]]\\. \\)\\(\\[^[:digit:]\\].*?\\)" nil t)
(replace-match "\\1\\,(replace-regexp-in-string " ;; here's a line break
" " " (match-string 2))" t nil))
)
)
It neither work - nor give an error.
Actually it would be better to have a separate defun to act on a string. This way it will be easy to expand the code to have multiple substitutions on the replace-match.
There are two issues with your code:
A period in a regexp matches "anything except newline," so your .*? will never include a newline character.
The \,(...) regexp replacement construct is only available interactively. If issue #1 were resolved, you'd get an error (error "Invalid use of '\\' in replacement text"). Programmatically, you have to write the code yourself, eg: (replace-match (concat (match-string 1) (replace-regexp-in-string "\n" " " (match-string 2)))).
I think you'd be better off not relying on regexps to do the heavy lifting here. This works for me:
(defun massage-list (start end)
(interactive "r")
(save-excursion
(save-restriction
(narrow-to-region start end)
(goto-char start)
(while (progn (forward-line) (= (point) (line-beginning-position)))
(when (not (looking-at "^[[:digit:]]+\\."))
(delete-indentation)
(beginning-of-line))))))
Try something like this code. It's not the shortest possible but rather something straigthforward.
(defun joining-lines(start end)
(interactive "r")
(let ((newline-string "~~~"))
(save-restriction
(narrow-to-region start end)
(mark-whole-buffer)
(replace-string "\n" newline-string)
(goto-char start)
(while (re-search-forward (concat newline-string "\\([[:digit:]]+. \\)") nil t)
(replace-match "\n\\1" nil nil))
(mark-whole-buffer)
(replace-string newline-string " "))))
Here's a solution using an external defun:
(defun capturing-paragraphs (start end)
(interactive "r")
(save-restriction
(narrow-to-region start end)
(goto-char (point-min))
(while (search-forward-regexp "^\\(^[[:digit:]]+\\.[^[:digit:]]+$\\)" nil t) (replace-match (multiple-find-replace-in-match) t nil))))
(defun multiple-find-replace-in-match ()
"Returns a string based on current regex match."
(let (matchedText newText)
(setq matchedText
(buffer-substring-no-properties
(match-beginning 1) (match-end 1)))
(setq newText
(replace-regexp-in-string "\n" "" matchedText) )
newText))
it works only if there's no figures in the text. But this solution is straighforward to expand - to add new replacements on a matched string.
ESS/Stata mode in emacs incorrectly indents lines that follow lines ending in operators. It seems to incorrectly interpret these lines as multiline commands.
For example:
gen foo = 1
/* generate another variable */
gen bar = 1
The line "gen bar = 1" should not be indented. It looks like EMACS interprets the trailing slash in the comment as an operator, and thinks this line of code spans two lines.
In fact, multiline commands in stata have 3 trailing slashes, and newlines without 3 trailing slashes indicate the end of a statement. e.g. the following indentation would be correct:
gen bar = 1
gen ///
foo = 1
Is there something I can put in my .emacs to correct this behavior? I don't want to give up automatic tabbing completely - it works very well for everything except comments that /* look like this */.
Thanks,
Pnj
You're right, ESS interprets the trailing / as an indication of line continuation. This is hard-coded into the function ess-continued-statement-p, so to modify the behaviour you have to rewrite the code. The following code (in your .emacs) works for your examples.
(eval-after-load 'ess-mode
'(defun ess-continued-statement-p ()
"this is modified code"
(let ((eol (point)))
(save-excursion
(cond ((memq (preceding-char) '(nil ?\, ?\; ?\} ?\{ ?\]))
nil)
;; ((bolp))
((= (preceding-char) ?\))
(forward-sexp -2)
(looking-at "if\\b[ \t]*(\\|function\\b[ \t]*(\\|for\\b[ \t]*(\\|while\\b[ \t]*("))
((progn (forward-sexp -1)
(and (looking-at "else\\b\\|repeat\\b")
(not (looking-at "else\\s_\\|repeat\\s_"))))
(skip-chars-backward " \t")
(or (bolp)
(= (preceding-char) ?\;)))
(t
(progn (goto-char eol)
(skip-chars-backward " \t")
(or (and (> (current-column) 1)
(save-excursion (backward-char 1)
;;;; Modified code starts here: ;;;;
(or (looking-at "[-:+*><=]")
(and (looking-at "/")
(save-excursion (backward-char 1)
(not (looking-at "*")))))))
;;;; End of modified code ;;;;
(and (> (current-column) 3)
(progn (backward-char 3)
(looking-at "%[^ \t]%")))))))))))
In TextMate, one can use ctrl-shift-w to wrap text in an Open/Close tag and ctrl-shift-cmd-w to wrap each line in a region in Open/Close tags. How can I implement this same functionality in Emacs using emacs lisp?
emacs
becomes
<p>emacs</p>
And ...
emacs
textmate
vi
becomes
<li>emacs</li>
<li>textmate</li>
<li>vi</li>
This answer gives you a solution for wrapping the region (once you modify it to use angle brackets).
This routine will prompt you for the tag to use, and should tag every line in the region with an open/close tag of that type:
(defun my-tag-lines (b e tag)
"'tag' every line in the region with a tag"
(interactive "r\nMTag for line: ")
(save-restriction
(narrow-to-region b e)
(save-excursion
(goto-char (point-min))
(while (< (point) (point-max))
(beginning-of-line)
(insert (format "<%s>" tag))
(end-of-line)
(insert (format "</%s>" tag))
(forward-line 1)))))
*Note: *If you wanted the tag to always be li, then remove the tag argument, remove the text \nMTag for line: from the call to interactive, and update the insert calls to just insert the "<li\>" as you would expect.
For sgml-mode deratives, mark region to tagify, type M-x sgml-tag, and type the tag name you like to use (press TAB to get list of available HTML elements). Altough, this method does not allow you to tagify each line in a region, you can work around this by recording a keyboard macro.
yasnippet is a particularly good implementation of Textmate's snippet syntax for Emacs. With that you can import all of Textmate's snippets. If you install it then, this snippet that I wrote should do what you want:
(defun wrap-region-or-point-with-html-tag (start end)
"Wraps the selected text or the point with a tag"
(interactive "r")
(let (string)
(if mark-active
(list (setq string (buffer-substring start end))
(delete-region start end)))
(yas/expand-snippet (point)
(point)
(concat "<${1:p}>" string "$0</${1:$(replace-regexp-in-string \" .*\" \"\" text)}>"))))
(global-set-key (kbd "C-W") 'wrap-region-or-point-with-html-tag)
EDIT: (Okay this is my last attempt at fixing this. It is exactly like Textmate's version. It even ignores characters after a space in the end tag)
Sorry I misread your question. This function should edit each line in the region.
(defun wrap-lines-in-region-with-html-tag (start end)
"Wraps the selected text or the point with a tag"
(interactive "r")
(let (string)
(if mark-active
(list (setq string (buffer-substring start end))
(delete-region start end)))
(yas/expand-snippet
(replace-regexp-in-string "\\(<$1>\\).*\\'" "<${1:p}>"
(mapconcat
(lambda (line) (format "%s" line))
(mapcar
(lambda (match) (concat "<$1>" match "</${1:$(replace-regexp-in-string \" .*\" \"\" text)}>"))
(split-string string "[\r\n]")) "\n") t nil 1) (point) (point))))
This variant on Trey's answer will also indent the html correctly.
(defun wrap-lines-region-html (b e tag)
"'tag' every line in the region with a tag"
(interactive "r\nMTag for line: ")
(setq p (point-marker))
(save-excursion
(goto-char b)
(while (< (point) p)
(beginning-of-line)
(indent-according-to-mode)
(insert (format "<%s>" tag))
(end-of-line)
(insert (format "</%s>" tag))
(forward-line 1))))