Forward sentence by comma by partial sentence in org - emacs

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

Related

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

org-mode include ignoring export settings

I have one org mode document that includes other org mode documents. The parent document should be exportable to pdf and each of the children should be aswell. Here is an example:
index.org
#+TITLE: Test Title
* Intro
This file must be exportable
* Heading 1
#+INCLUDE: doc1.org :minlevel 2 :only-contents t
doc1.org
#+TITLE: Inner title
This file must be exportable by itself aswell
* Heading 2
And here is some text
Exporting doc1.org produces the expected:
But exporting index.org yields (notice the title):
Is there a way to suppress the export options of included org documents?
The #+INCLUDE mechanism can include a portion of the file, so you can say
#+INCLUDE: doc1.org :minlevel 2 :only-contents t :lines "2-"
and have it skip the #+TITLE line in the included file. See http://orgmode.org/org.html#Include-files.
I made this ugly fix by overriding some org mode elisp. I put this in my .emacs and now things work as expected. Maybe I will post a patch to org mode when I get the time.
(defun fd--org-doc-begin ()
"Skip all the initial export options"
(save-excursion
(goto-char (point-min))
(while (and (or
(looking-at "[ \t]*#+")
(looking-at "[ \t]*$"))
(progn (next-line) (< (point) (point-max))))
(beginning-of-line))
(point)))
;;; This was overriden from ox.el
(defun org-export--prepare-file-contents
(file &optional lines ind minlevel id footnotes with-export-options)
"Prepare contents of FILE for inclusion and return it as a string.
When optional argument LINES is a string specifying a range of
lines, include only those lines.
Optional argument IND, when non-nil, is an integer specifying the
global indentation of returned contents. Since its purpose is to
allow an included file to stay in the same environment it was
created (e.g., a list item), it doesn't apply past the first
headline encountered.
Optional argument MINLEVEL, when non-nil, is an integer
specifying the level that any top-level headline in the included
file should have.
Optional argument ID is an integer that will be inserted before
each footnote definition and reference if FILE is an Org file.
This is useful to avoid conflicts when more than one Org file
with footnotes is included in a document.
Optional argument FOOTNOTES is a hash-table to store footnotes in
the included document.
Optional argument WITH-EXPORT-OPTIONS will stop this function
from ignoring export options at the beginning of the file."
(with-temp-buffer
(insert-file-contents file)
(when (not with-export-options)
(narrow-to-region (fd--org-doc-begin) (point-max)))
(when lines
(let* ((lines (split-string lines "-"))
(lbeg (string-to-number (car lines)))
(lend (string-to-number (cadr lines)))
(beg (if (zerop lbeg) (point-min)
(goto-char (point-min))
(forward-line (1- lbeg))
(point)))
(end (if (zerop lend) (point-max)
(goto-char (point-min))
(forward-line (1- lend))
(point))))
(narrow-to-region beg end)))
;; Remove blank lines at beginning and end of contents. The logic
;; behind that removal is that blank lines around include keyword
;; override blank lines in included file.
(goto-char (point-min))
(org-skip-whitespace)
(beginning-of-line)
(delete-region (point-min) (point))
(goto-char (point-max))
(skip-chars-backward " \r\t\n")
(forward-line)
(delete-region (point) (point-max))
;; If IND is set, preserve indentation of include keyword until
;; the first headline encountered.
(when (and ind (> ind 0))
(unless (eq major-mode 'org-mode)
(let ((org-inhibit-startup t)) (org-mode)))
(goto-char (point-min))
(let ((ind-str (make-string ind ?\s)))
(while (not (or (eobp) (looking-at org-outline-regexp-bol)))
;; Do not move footnote definitions out of column 0.
(unless (and (looking-at org-footnote-definition-re)
(eq (org-element-type (org-element-at-point))
'footnote-definition))
(insert ind-str))
(forward-line))))
;; When MINLEVEL is specified, compute minimal level for headlines
;; in the file (CUR-MIN), and remove stars to each headline so
;; that headlines with minimal level have a level of MINLEVEL.
(when minlevel
(unless (eq major-mode 'org-mode)
(let ((org-inhibit-startup t)) (org-mode)))
(org-with-limited-levels
(let ((levels (org-map-entries
(lambda () (org-reduced-level (org-current-level))))))
(when levels
(let ((offset (- minlevel (apply #'min levels))))
(unless (zerop offset)
(when org-odd-levels-only (setq offset (* offset 2)))
;; Only change stars, don't bother moving whole
;; sections.
(org-map-entries
(lambda ()
(if (< offset 0) (delete-char (abs offset))
(insert (make-string offset ?*)))))))))))
;; Append ID to all footnote references and definitions, so they
;; become file specific and cannot collide with footnotes in other
;; included files. Further, collect relevant footnote definitions
;; outside of LINES, in order to reintroduce them later.
(when id
(let ((marker-min (point-min-marker))
(marker-max (point-max-marker))
(get-new-label
(lambda (label)
;; Generate new label from LABEL by prefixing it with
;; "-ID-".
(format "-%d-%s" id label)))
(set-new-label
(lambda (f old new)
;; Replace OLD label with NEW in footnote F.
(save-excursion
(goto-char (+ (org-element-property :begin f) 4))
(looking-at (regexp-quote old))
(replace-match new))))
(seen-alist))
(goto-char (point-min))
(while (re-search-forward org-footnote-re nil t)
(let ((footnote (save-excursion
(backward-char)
(org-element-context))))
(when (memq (org-element-type footnote)
'(footnote-definition footnote-reference))
(let* ((label (org-element-property :label footnote)))
;; Update the footnote-reference at point and collect
;; the new label, which is only used for footnotes
;; outsides LINES.
(when label
(let ((seen (cdr (assoc label seen-alist))))
(if seen (funcall set-new-label footnote label seen)
(let ((new (funcall get-new-label label)))
(push (cons label new) seen-alist)
(org-with-wide-buffer
(let* ((def (org-footnote-get-definition label))
(beg (nth 1 def)))
(when (and def
(or (< beg marker-min)
(>= beg marker-max)))
;; Store since footnote-definition is
;; outside of LINES.
(puthash new
(org-element-normalize-string (nth 3 def))
footnotes))))
(funcall set-new-label footnote label new)))))))))
(set-marker marker-min nil)
(set-marker marker-max nil)))
(org-element-normalize-string (buffer-string))))

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: how to write a defun which acts on region, but acts on point if there's no region?

I write a simple defun for a region, and I want to apply it even if there's no region – i.e. call it with no selection at all. I thought I could do something like the following:
(defun region-study (strt end)
(interactive "r")
(if (= strt end)
(progn ....) ;; then
(progn ....))) ;; else
But it doesn't work. As it turns out, when you call (interactive "r") with no region it doesn't just set boundaries to be equal. Try this:
(defun region-study (strt end)
(interactive "r")
(message "strt=%d; end=%d" strt end))
So my question is that: "how to write a defun which acts on region, but acts on point if there's no region?"
Edit:
So I wanted to put selection in brackets or just to insert brackets and (backward-char 1). Here's a solution:
(defun put-in-lft-rit (lft rit)
(interactive "k")
(if (use-region-p) ;; act on region
(progn
(setq pP (point))
(setq strt (region-beginning))
(setq end (region-end))
(setq meat (buffer-substring-no-properties strt end))
(setq news (concat lft meat rit))
(delete-region strt end)
(goto-char strt)
(insert news)
(if (= pP strt)
(goto-char strt) ; then
(goto-char (+ end 1)))) ; else
(progn ;; act on point
(insert lft rit)
(backward-char 1))))
(defun bk-put-in-braces ()
(interactive)
(put-in-lft-rit "(" ")"))
(defun bk-put-in-curly-braces ()
(interactive)
(put-in-lft-rit "{" "}"))
(defun bk-put-in-quotes ()
(interactive)
(put-in-lft-rit "'" "'"))
(defun bk-put-in-double-quotes ()
(interactive)
(put-in-lft-rit "\"" "\""))
(defun bk-put-in-square-brackes ()
(interactive)
(put-in-lft-rit "[" "]"))
And then you bind in .emacs:
(global-set-key (kbd "C-<f9>") 'bk-put-in-square-brackes)
(global-set-key (kbd "<f9>") 'bk-put-in-curly-braces)
(global-set-key (kbd "S-<f7>") 'bk-put-in-quotes)
(global-set-key (kbd "S-<f8>") 'bk-put-in-double-quotes)
(global-set-key (kbd "S-<f9>") 'bk-put-in-braces)
That's it! Should be working in all modes.
Edit2:
#phils
Thanks. You are definetely right. One thing though - my code had an additional feature of leaving the point at the beginning or end of the region - depending on where it was in the selection. Here's Your code with this feature added:
(defun put-in-lft-rit (lft rit)
(interactive "k")
(if (use-region-p) ;; act on region
(let ((strt (region-beginning))
(end (region-end))
(pP (point)))
(save-excursion
(goto-char end)
(insert rit)
(goto-char strt)
(insert lft))
(if (= pP strt)
(goto-char strt) ; then
(goto-char (+ end 1)))) ; else
(progn ;; act on point
(insert lft rit)
(backward-char 1))))
A few notes on your solution...
It's good practice to avoid unnecessary global-scope setqs. Use (let) instead to define a temporary scope for your variables.
You are doing a lot more work than required. Instead of copying the region, concatenating that copy and the delimiters into a 'news' variable, deleting the region, and then inserting 'news', all you need to do is insert the delimiter characters at the beginning and end of the region.
(In general, if you try to "think like an editor" when writing elisp, and focus on manipulating buffers rather than variables, you'll generally wind up with more efficient code.)
save-excursion is very useful (along with several other save- and with- forms).
 
(defun put-in-lft-rit (lft rit)
(interactive "k")
(if (use-region-p) ;; act on region
(let ((strt (region-beginning))
(end (region-end)))
(save-excursion
(goto-char end)
(insert rit)
(goto-char strt)
(insert lft)))
(progn ;; act on point
(insert lft rit)
(backward-char 1))))
use-region-p should return t if your function should act on the region instead of at a point.
You may like to use the function region-or-word-at-point defined in thingatpt+.el

Wrap selection in Open/Close Tag like TextMate?

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