Custom toggler? - emacs

I want to have toggler which would add/remove ".. " (there's a space -- but I can't make it more pronounced) string in front of every line above (point). Here's my best bet:
(defun rst-comment-above (Point)
(interactive "d")
(save-excursion
(goto-char 1)
(cond
((numberp (get this-command 'state))
((replace-regexp "^\\.\\. " "" nil (point) (get this-command 'state)))
(put this-command 'state ""))
(t
(replace-regexp "^" ".. " nil (point) Point)
(put this-command 'state Point))
)))
it works for the first time, but for the second it says:
(invalid-function
(replace-regexp "^\\.\\. " "" nil (point) (get this-command (quote state))))
Edit:
#user4815162342:
So I comment the thing above:
Then I insert new lines:
Then I want to uncomment the thing, and I get:
But probably its not that important. I do not generally enter anything in the commented area. I just note that the issue. What is some what more important -- is to store the 'state of the given file across the sessions. Is it hard to implement?

The error comes from the extra set of parentheses on the line where you call replace-regexp. That line should be:
(replace-regexp "^\\.\\. " "" nil (point) (get this-command 'state))
There are several other problems with your code.
Storing the current value of point doesn't work well because you add
characters to the buffer, which makes the point move forward. This makes
(once the above syntax error is fixed) the function miss the last several
instances of "..".
The fix is to store the point marker.
You should be using (point-min) instead of hard-coding the buffer
beginning to 1, or your code will fail to work when buffer narrowing is in
effect.
Finally, replace-regexp, as its documentation states, is not meant to be
called from Lisp programs.
Here is a revised version of your function:
(defun rst-comment-above ()
(interactive)
(let ((pm (point-marker))
(prev-marker (get this-command 'rst-prev-marker)))
(save-excursion
(goto-char (point-min))
(cond ((null prev-marker)
(while (< (point) pm)
(insert "..")
(forward-line 1))
(put this-command 'rst-prev-marker pm))
(t
(while (< (point) prev-marker)
(when (looking-at "^\\.\\.")
(replace-match ""))
(forward-line 1))
(put this-command 'rst-prev-marker nil))))))

Any reason why you don't use M-; in rst-mode?

Related

Forward sentence by comma by partial sentence in org

Strike M-e in org which invokes org-forward-sentence and thus move point to end of the sentence.
I desire to move by comma. When refer to org-forward-sentence, notice the last two lines of
(let ((sentence-end (concat (sentence-end) "\\|^\\*+ .*$")))
(call-interactively #'forward-sentence)))))))
From the completed definition.
(defun org-forward-sentence (&optional _arg)
"Go to end of sentence, or end of table field.
This will call `forward-sentence' or `org-table-end-of-field',
depending on context."
(interactive)
(if (and (org-at-heading-p)
(save-restriction (skip-chars-forward " \t") (not (eolp))))
(save-restriction
(narrow-to-region (line-beginning-position) (line-end-position))
(call-interactively #'forward-sentence))
(let* ((element (org-element-at-point))
(contents-end (org-element-property :contents-end element))
(table (org-element-lineage element '(table) t)))
(if (and table
(>= (point) (org-element-property :contents-begin table))
(< (point) contents-end))
(call-interactively #'org-table-end-of-field)
(save-restriction
(when (and contents-end
(> (point-max) contents-end)
;; Skip blank lines between elements.
(< (org-element-property :end element)
(save-excursion (goto-char contents-end)
(skip-chars-forward " \r\t\n"))))
(narrow-to-region (org-element-property :contents-begin element)
contents-end))
;; End of heading is considered as the end of a sentence.
(let ((sentence-end (concat (sentence-end) "\\|^\\*+ .*$")))
(call-interactively #'forward-sentence)))))))
Then changed dot to comma
(let ((sentence-end (concat (sentence-end) "\\|^\\*+ ,*$"))) ;;changee . to ,
(call-interactively #'forward-sentence)))))))
However, it proved wrong.
Where should I change within the original function.
Define it as
(def org-forward-partial-sentence (&optional arg)
and (global-set-key "\C-m"
That . has special meaning in a regex context, see (emacs)Regexps in the manual.
A very simplistic modification could be,
(concat (sentence-end) "\\|^\\*+ .*$\\|,")
to move to , as well.
Instead of changing the entire function, you could just let bind sentence-end around org-forward-sentence, eg.
(defun my-org-forward-sentence ()
(interactive)
(let ((sentence-end (concat (sentence-end) "\\|,")))
(call-interactively #'org-forward-sentence)))

Split lines of current paragraph in Emacs

I want to add a function (para2lines) to Emacs by which I can split the current paragraph into its sentences and print them line by line in a separate buffer. Following is code in Racket/Scheme:
(define (p2l paraString)
(define lst (string-split paraString ". "))
(for ((i lst))
(displayln i)))
Testing:
(p2l "This is a test. For checking only. Only three lines.")
Output:
This is a test.
For checking only.
Only three lines.
In Emacs Lisp, I could manage following code:
(defun pl (ss)
(interactive)
(let ((lst (split-string (ss))))
(while lst
(print (pop lst)))))
But I do not know how to get the text from the paragraph with current position. How can I correct this function?
Edit: basically, I want to read it as separate lines but want to save it as paragraph.
Here's an example that might help you on your way. It will do your conversion to the current paragraph (i.e. where the cursor is positioned), rather than to a new buffer. You could modify this to pass a string to your function if that's what you require.
(defun p2l ()
"Format current paragraph into single lines."
(interactive "*")
(save-excursion
(forward-paragraph)
(let ((foo (point)))
(backward-paragraph)
(replace-regexp "\n" " " nil (1+ (point)) foo)
(backward-paragraph)
(replace-regexp "\\. ?" ".\n" nil (point) foo))))
I would just run Emacs commands or write a macro to convert a paragraph to single-sentence lines, but maybe you are really just wanting to read wrapped paragraphs as lines, thus the need to have an Emacs command.
Here's something that will grab the current paragraph, insert a new buffer *Lines*, and then convert sentences to lines.
(defun para-lines ()
"Split sentences of paragraph to lines in new buffer."
(interactive)
;; Move the paragraph to a new buffer.
(let ((b (generate-new-buffer "*Lines*")))
(with-output-to-temp-buffer b
(let ((beg (save-excursion (forward-paragraph -1) (point)))
(end (save-excursion (forward-paragraph +1) (point))))
(princ (buffer-substring-no-properties beg end))))
;; Switch to new buffer
(with-current-buffer b
;; Since the name starts with "*", shut off Help Mode
(fundamental-mode)
;; Make sure buffer is writable
(setq buffer-read-only nil)
;; From the start of the buffer
(goto-char (point-min))
;; While not at the end of the buffer
(while (< (point) (point-max))
(forward-sentence 1)
;; Delete spaces between sentences before making new new line
(delete-horizontal-space)
;; Don't add a new line, if already at the end of the line
(unless (= (line-end-position) (point))
(newline))))))
To avoid using forward-sentence, and just use a regular expression, use re-search-forward. For instance, to match semi-colons as well as periods.
(defun para-lines ()
"Split sentences of paragraph to lines in new buffer."
(interactive)
;; Move the paragraph to a new buffer.
(let ((b (generate-new-buffer "*Lines*")))
(with-output-to-temp-buffer b
(let ((beg (save-excursion (forward-paragraph -1) (point)))
(end (save-excursion (forward-paragraph +1) (point))))
(princ (buffer-substring-no-properties beg end))))
;; Switch to new buffer
(with-current-buffer b
;; Since the name starts with "*", shut off Help Mode
(fundamental-mode)
;; Make sure buffer is writable
(setq buffer-read-only nil)
;; From the start of the buffer
(goto-char (point-min))
;; While not at the end of the buffer
(while (< (point) (point-max))
(re-search-forward "[.;]\\s-+" nil t)
;; Delete spaces between sentences before making new new line
(delete-horizontal-space)
;; Don't add a new line, if already at the end of the line
(unless (= (line-end-position) (point))
(newline))))))

How to search for a complete org headline that was saved as a variable

The function (org-heading-components) and (org-element-property) produce integers for the number of stars and also for the priority. I'd like to store the entire headline as a variable and then use re-search-forward (or a similar function) to go back to that heading, but I foresee the problem that will occur when it cannot find an integer. I need to store the whole heading as a variable, because I often have todo entries with duplicate titles but the other components are diferent.
For example, the following todo:
** Active [#A] Ask the geniuses on stackoverflow how to do this. :lawlist:
when evaluated with (org-heading-components) looks like this:
(2 2 "Active" 65 "Ask the geniuses on stackoverflow how to do this." ":lawlist:")
So, when storing that as a variable and later using re-search-forward there will be problems because 2 2 is not the same as **, and 65 is not the same as [#A].
(defun lawlist ()
(interactive)
(let* (
(beg (point))
(complete-heading (org-heading-components) ))
* * *
(goto-char (point-min))
(re-search-forward complete-heading nil t) ))
You should be able to convert the output as follows:
The first # is the current level (# of stars)
The second number is the reduced headline level, applicable if org-odd-levels-only is set, but this is not regarding output.
Todo keyword
Priority character (65 is ASCII code for A)
Headline text
Tags or nil
The following will return the headline string as shown in the buffer. It will not work with re-search-forward but will work with search-forward (It does not escape any characters).
(defun zin/search-test ()
(interactive)
(let ((head (org-element-interpret-data (org-element-at-point))))
(message "%s" (format "%s" (car (split-string head "\n"))))))
This does not set it to any variable, you'll have to wrap it in an appropriate function that will set your desired variable. Then use (search-forward <var> nil t) to match it, without it erroring out if it cannot find it.
There's a brilliant part of org that might suit you: org-id-copy and
org-id-goto. It works with precision across buffers and sessions:
org-id-copy produces a string. You can feed that string to
org-id-goto which will take you to that heading. Even if you've
closed the original buffer. Even if you've restarted Emacs.
EDIT (December 15, 2013):  Updated solution based upon the variable org-heading-regexp (defined within org.el) and a modification thereof to include (if it exists) a second line containing a deadline - i.e., lawlist-org-heading-regexp. The revision also includes a nifty function regexp-quote that was just taught to me by #Drew over on superuser: https://superuser.com/questions/688781/how-to-highlight-string-and-unhighlight-string-in-buffer-make-overlay?noredirect=1#comment874515_688781  (buffer-substring-no-properties beg end) is used to set the string as a variable.
EDIT (December 17, 2013):   Added isearch-highlight and isearch-dehighlight, and commented out highlight-regexp and unhighlight-regexp. When moving the point around with more complex functions, highlight-regexp does not reliably highlight the entire string -- this may be because the screen has not refreshed, or it may also be caused by other factors -- e.g., hl-line-mode, etc.) -- placing various sit-for 0 did not fix the issue with highlight-regexp -- isearch-highlight works better.
EDIT (January 6, 2014):  See also this related thread for a complete regexp to match any element of the entire todo from stars through to the end of the notes:  https://stackoverflow.com/a/20960301/2112489
(require 'org)
(defvar lawlist-org-heading-regexp
"^\\(\\*+\\)\\(?: +\\(.*?\\)\\)?[ \t]*\\(\n.*DEADLINE.*$\\)"
"Match headline, plus second line with a deadline.")
(defun example ()
(interactive)
(switch-to-buffer (get-buffer-create "foo"))
(org-mode)
(insert "* Example\n\n")
(insert "** Active [#A] This is an active todo. :lawlist:\n")
(insert " DEADLINE: <2013-12-15 Sun 08:00> SCHEDULED: <2013-12-15 Sun>\n\n")
(insert "** Next-Action [#B] This is an inactive todo. :lawlist:\n")
(insert " DEADLINE: <2013-12-16 Mon 08:00> SCHEDULED: <2013-12-16 Mon>")
(goto-char (point-min))
(sit-for 2)
(re-search-forward (regexp-quote "** Active [#A] "))
(sit-for 2)
(let ((init-pos (point)))
(org-back-to-heading t)
(let* (
lawlist-item-whole
lawlist-item-partial
(beg (point)))
(if (and
(looking-at org-heading-regexp)
(and (looking-at lawlist-org-heading-regexp) (match-string 3)))
(re-search-forward lawlist-org-heading-regexp nil t)
(re-search-forward org-heading-regexp nil t))
(let ((end (point)))
(setq lawlist-item-whole (buffer-substring-no-properties beg end))
(setq lawlist-item-partial (buffer-substring-no-properties beg init-pos))
(re-search-backward (regexp-quote lawlist-item-whole) nil t)
;; (highlight-regexp (regexp-quote lawlist-item-whole))
(isearch-highlight beg end)
(sit-for 2)
;; (unhighlight-regexp (regexp-quote lawlist-item-whole))
(isearch-dehighlight)
(re-search-forward (regexp-quote lawlist-item-partial) nil t)
(sit-for 2)
(kill-buffer "foo")))))
EDIT (October 27, 2013):  Prior solution that is being preserved temporarily as a historical part of the evolution process towards a final answer. However, it is no longer a preferred method.
(defun lawlist-org-heading-components ()
(org-back-to-heading t)
(if (let (case-fold-search) (looking-at org-complex-heading-regexp))
(concat
(cond
((equal (org-match-string-no-properties 1) "**")
"^[*][*]")
((equal (org-match-string-no-properties 1) "*")
"^[*]"))
(cond
((and (match-end 2) (aref (match-string 2) 1))
(concat " " (org-match-string-no-properties 2))))
(cond
((and (match-end 3) (aref (match-string 3) 2))
(concat " \\" (org-match-string-no-properties 3))))
(cond
((and (match-end 4) (aref (match-string 4) 3))
(concat " " (org-match-string-no-properties 4))))
(cond
((and (match-end 5) (aref (match-string 5) 4))
(concat " " (org-match-string-no-properties 5)))))))

Define a copy-section command in Emacs

I would like to set up a command that put the content of the lines between two § characters without moving the point (not including the lines containg the §).
Here is my current attempt
(defun copy-section ()
"Copy current section, that is lines between two §."
(interactive)
(save-excursion
(when (not (search-backward-regexp "§" nil t))
(goto-char (point-min)) )
(forward-line 1)
(when (not (search-forward-regexp "§" nil t))
(goto-char (point-max)) )
(move-beginning-of-line nil)
(kill-ring-save (mark) (point)) ) )
It works well but the remarks in the documentation about moving around the mark being bad style make me think taht there is a better way to achieve the same result.
Does saving position into variable (which I do not know how to do it) allows for a cleaner function.
Part of the code above comes from ergoemacs.
No "regexp" form needed as only a char is looked for
(defun copy-section ()
"Copy current section, that is lines between two §."
(interactive)
(save-excursion
(let* ((start (and (search-backward "§" nil t)
(forward-line 1)
(point)))
(end (progn (and start (search-forward "§" nil t))
(forward-line -1)
(end-of-line)
(point))))
(and start end (kill-new (buffer-substring-no-properties start end))))))
This version saves the beginning and end of your section in temporary local variables, and doesn't use the mark at all:
(defun copy-section ()
"Copy current page as defined by form feed characters."
(interactive)
(let (start end)
(save-excursion
(when (not (search-backward-regexp "§" nil t))
(goto-char (point-min)) )
(forward-line 1)
(setq start (point))
(when (not (search-forward-regexp "§" nil t))
(goto-char (point-max)) )
(move-beginning-of-line nil)
(setq end (point))
(kill-ring-save start end))))

Emacs: capture paragraphs and act on each

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.