[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: buffer substring of only visible text
From: |
Felix Dietrich |
Subject: |
Re: buffer substring of only visible text |
Date: |
Wed, 21 Sep 2022 13:34:24 +0200 |
User-agent: |
Gnus/5.13 (Gnus v5.13) Emacs/28.1 (gnu/linux) |
Hello Samuel,
Samuel Wales <samologist@gmail.com> writes:
> i want to copy visible text from a region in a buffer, into a string.
> if any invisible regions are in the region, i want them to not be in
> the string. that is, i want the visible intervals in the copied
> region to be merely appended. when i INSERT the resulting string into
> the new buffer, i want any text properties that i specify to still
> exist. htmlize.el has a function, buffer-substring-no-invisible,
> which does not include any text properties at all. it works, but i'd
> like to include at least one text property, which i want to specify.
>
> i am looking for a know a cookbook formula to do this really
> straightforwardly.
I do not know any cookbook solution for this problem, but you have
already found a (fairly short and straightforward) function that almost
does what you described; with a few minor modifications you should be
able to get what you want (almost untested):
#+begin_src emacs-lisp
(defun my/buffer-substring-with-properties (start end props)
;; Copy the specified property from the specified region of the
;; buffer to the target string. We cannot rely on Emacs to copy the
;; property because we want to handle properties coming from both
;; text properties and overlays.
(let ((text (buffer-substring-no-properties start end)))
(dolist (p props)
(htmlize-copy-prop p start end text))
text))
(defun my/buffer-substring-no-invisible (beg end &optional props)
;; Like buffer-substring-no-properties, but don't copy invisible
;; parts of the region. Where buffer-substring-no-properties
;; mandates an ellipsis to be shown, htmlize-ellipsis is inserted.
(let ((pos beg)
visible-list invisible show last-show next-change)
;; Iterate over the changes in the `invisible' property and filter
;; out the portions where it's non-nil, i.e. where the text is
;; invisible.
(while (< pos end)
(setq invisible (get-char-property pos 'invisible)
next-change (htmlize-next-change pos 'invisible end)
show (htmlize-decode-invisibility-spec invisible))
(cond ((eq show t)
(push (my/buffer-substring-with-properties pos next-change
props)
visible-list))
((and (eq show 'ellipsis)
(not (eq last-show 'ellipsis))
;; Conflate successive ellipses.
(push htmlize-ellipsis visible-list))))
(setq pos next-change last-show show))
(htmlize-concat (nreverse visible-list))))
#+end_src
The function ‘my/buffer-substring-no-invisible’ only adds an additional
parameter PROPS to ‘htmlize-buffer-substring-no-invisible’ and replaces
the call to ‘htmlize-get-text-with-display’ with a call to
‘my/buffer-substring-with-properties’ that takes the PROPS parameter to
copy not only the two fixed properties ‘display’ and ‘htmlize-link’, as
does ‘htmlize-get-text-with-display’, but allow specifying the desired
properties to copy when calling the function.
Text that has the ‘invisible’ property may be replaced with an ellipsis
(depending on ‘buffer-invisibility-spec’). If you preferred there
rather be no ellipsis, adjust the cond-form or bind ‘htmlize-ellipsis’
to the empty string "".
As the comment at the top of ‘htmlize-copy-prop’ suggests, Emacs may
provide more efficient means to copy text properties if you do not need
the overlay properties. I cannot help you with the details of that,
though, but maybe the sections on text and overlay properties in the
Emacs Lisp handbook can provide you with the necessary clues [1][2].
Footnotes:
[1] (info "(elisp) Text Properties")
<https://www.gnu.org/software/emacs/manual/html_node/elisp/Text-Properties.html>
[2] (info "(elisp) Overlay Properties")
<https://www.gnu.org/software/emacs/manual/html_node/elisp/Overlay-Properties.html>
--
Felix Dietrich