unofficial mirror of help-gnu-emacs@gnu.org
 help / color / mirror / Atom feed
From: Felix Dietrich <felix.dietrich@sperrhaken.name>
To: Samuel Wales <samologist@gmail.com>
Cc: help-gnu-emacs@gnu.org
Subject: Re: buffer substring of only visible text
Date: Wed, 21 Sep 2022 13:34:24 +0200	[thread overview]
Message-ID: <8735clm05b.fsf@sperrhaken.name> (raw)
In-Reply-To: <CAJcAo8t_+GAgS-jyv=yd=-VFVYJJ5cwqrDvkJtMNOba2t+OU_g@mail.gmail.com> (Samuel Wales's message of "Tue, 20 Sep 2022 18:08:03 -0700")

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



  parent reply	other threads:[~2022-09-21 11:34 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-09-21  1:08 buffer substring of only visible text Samuel Wales
2022-09-21  1:34 ` Emanuel Berg
2022-09-21 11:34 ` Felix Dietrich [this message]
2022-09-21 22:57   ` Samuel Wales
2022-09-28 17:59     ` Felix Dietrich
2022-09-22  9:14 ` Michael Heerdegen

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://www.gnu.org/software/emacs/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=8735clm05b.fsf@sperrhaken.name \
    --to=felix.dietrich@sperrhaken.name \
    --cc=help-gnu-emacs@gnu.org \
    --cc=samologist@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).