Programmatically detect if any line in a buffer is wrapping? - emacs

I have an idea for a possibly cool/probably stupid emacs script which would dynamically resize text to fill available space.
One thing I can't seem to figure out is how to query the current buffer to see if any lines are currently being wrapped. How would I do it?

You can check if any lines are wrapped in the current buffer with function like this:
(defun wrapped-lines-p ()
(save-excursion
(goto-char (point-min))
(let ((long-line-regexp
(format "^.\\{%d\\}.+$" (window-body-width))))
(search-forward-regexp long-line-regexp nil t))))
As noted in the comments, this doesn't take into account the buffer's font size. Since buffers can have a mix of different sized fonts, the window text pixel size needs to be tested. Try this:
(defun wrapped-lines-p ()
(let ((window-width-pixels (window-body-width nil t)))
(> (car (window-text-pixel-size nil nil nil (1+ window-width-pixels)))
window-width-pixels)))

Note that "any lines are currently being wrapped" is a property of the window, not the buffer.
Given a window, you can scan it from top visible line to bottom and compare line length to window-width:
(defun window-long-lines-p ()
"Return t is any visible line in the current window is longer than window width."
(save-excursion
(move-to-window-line -1)
(let ((end (point)) here
found-long-line)
(move-to-window-line 0)
(while (and (not found-long-line)
(< (setq here (point)) end))
(when (< (window-width)
(- (progn (forward-line 1)
(point))
here))
(setq found-long-line t)
(message "long line: %d" (1- (line-number-at-pos)))))
found-long-line)))

Related

Pin/lock/fix text

With elisp it is possible to add overlays to parts of the buffer to hide them etc. I went through all the possible overlays and couldn't find a way to pin a selection. Is it possible to have a function that, given a selection in a buffer, pins this selection so that when you scroll up or down the selection is always shown? (a bit like what you have with Excel where you can lock some rows or columns so that they always appear on screen).
I wanted to do something like this but with (overlay-put new-overlay 'lock t) but there doesn't appear to be such overlay.
(defun hide-region-hide ()
"Hides a region by making an invisible overlay over it and save the
overlay on the hide-region-overlays \"ring\""
(interactive)
(let ((new-overlay (make-overlay (mark) (point))))
(push new-overlay hide-region-overlays)
(overlay-put new-overlay 'invisible t)
(overlay-put new-overlay 'intangible t)
(overlay-put new-overlay 'before-string
(if hide-region-propertize-markers
(propertize hide-region-before-string
'font-lock-face 'hide-region-before-string-face)
hide-region-before-string))
(overlay-put new-overlay 'after-string
(if hide-region-propertize-markers
(propertize hide-region-after-string
'font-lock-face 'hide-region-after-string-face)
hide-region-after-string))))
I came up with this solution that works pretty well:
(defvar-local pinned-buffer nil
"Variable to store the buffer that contains the pinned region.")
(defun region-unpin ()
"Unpin the current region"
(interactive)
(when pinned-buffer
(let ((window (get-buffer-window pinned-buffer 'visible)))
(setq-local pinned-buffer nil)
(quit-window t window))))
(defun region-pin ()
"Pin the current region to the top."
(interactive)
(when (use-region-p)
(let* ((regionp (buffer-substring (mark) (point)))
(buffer (get-buffer-create "tmp.ml"))
(mode major-mode))
(with-current-buffer buffer
(funcall mode)
(hide-mode-line-mode)
(goto-char (window-end))
(insert regionp)
(goto-char 0))
(setq-local window-min-height 1)
(setq-local pinned-buffer buffer)
(display-buffer-in-direction buffer '((direction . above)
(inhibit-same-window . t)
(window-height . fit-window-to-buffer)))
)))
This allows me to have a temporary window with the major mode of my current one, no modeline, the height of the window fits perfectly the selection and the cursor is set to the beginning of it to have the full text displayed in it but whenever I want to pin some more text it goes to the end of the buffer, insert the selected region and goes back up.

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

How do I get the region (selection) programmatically in Emacs Lisp?

I need to access the selection in Emacs buffer.
I have found this article How do I access the contents of the current region in Emacs Lisp?
and it helps me a lot.
But there is a problem. The first time I select (highlight) a region, it works okay, but when I press C-g, and move cursor normally to another place without highlighting any chars, I got a string from last mark to the current point while I expect an empty one.
Actually I need to implement a function which will return the current selection (highlighted) as a string, or empty string if nothing is highlighted. The following code may express me more clearly.
(defun get-search-term ()
(interactive)
(let (
(selection (buffer-substring-no-properties (region-beginning) (region-end))))
(if (= (length selection) 0)
(message "empty string")
(message selection))))
Any suggestions? Thanks a lot!
"r" specification of interactive is dumb. You're seeing why.
(defun get-search-term (beg end)
"message region or \"empty string\" if none highlighted"
(interactive (if (use-region-p)
(list (region-beginning) (region-end))
(list (point-min) (point-min))))
(let ((selection (buffer-substring-no-properties beg end)))
(if (= (length selection) 0)
(message "empty string")
(message selection))))
I don't mean "dumb" as in stupid and not useful; just that it doesn't care
about whether the mark is active or not. I think it predates
transient-mark-mode.
EDIT: Using (point-min) twice above makes the code harder to understand
when re-reading. Here is a better implementation:
(defun get-search-term (beg end)
"message region or \"empty string\" if none highlighted"
(interactive (if (use-region-p)
(list (region-beginning) (region-end))
(list nil nil)))
(message "%s" (if (and beg end)
(buffer-substring-no-properties beg end)
"empty string")))
Check variable mark-active eg. C-h v mark-active
==> mark-active is a variable defined in `C source code'.
Its value is nil
Local in buffer Apropos; global value is nil
Automatically becomes buffer-local when set in any fashion.
Documentation:
Non-nil means the mark and region are currently active in this buffer.
(defun get-search-term ()
(interactive)
(if mark-active
(let (
(selection (buffer-substring-no-properties (region-beginning) (region-end))))
(if (= (length selection) 0)
(message "empty string")
(message selection))
)
(error "mark not active"))
)