Subject: bug#29286: kill-visible/kill-ring-save-visible commands

From: [email-masked] (Charles A. Roelli)
Date: Mon, 13 Nov 2017 20:28:18 +0100

It can be convenient sometimes to kill text exactly as it is
displayed.  For example, if you have some text in a program hidden
with "hs-minor-mode", then want to copy part of the buffer including
the hidden text, the hidden text will still be part of the killed
text.  Or if you kill text in an Info node, you sometimes find that
you've also yanked some invisible text with it.  I wrote the following
commands to test omission of invisible text:

  (defun kill-visible-region (beg end &optional delete)
     (interactive (list (mark) (point) t))
     (let ((filter-buffer-substring-function 'visible-buffer-substring))
       (kill-ring-save beg end region)))

  (defun kill-ring-save-visible-region (beg end &optional delete)
     (interactive (list (mark) (point) nil))
     (let ((filter-buffer-substring-function 'visible-buffer-substring))
       (kill-ring-save beg end delete)))

  (defun visible-buffer-substring (beg end delete)
     "Return visible text in BEG to END in the current buffer.

  Delete if DELETE is non-nil."
     (let ((text "") (ellipse-p nil))
       (save-excursion
	 (goto-char beg)
	 (while (< (point) end)
	  (let ((invis (invisible-p (point))))
	    (cond ((eq invis nil)
		   (setq text (concat text (make-string
					    1 (char-after (point))))
			 ellipse-p nil))
		  ((eq invis t) (setq ellipse-p nil))
		  ((and invis (not ellipse-p))
		   (setq text (concat text (make-string 3 ?.))
			 ellipse-p t)))
	    (goto-char (1+ (point))))))
       (if delete (delete-region beg end))
       text))

They work for the purpose of killing text partially hidden by
hs-minor-mode, but the solution is not general, since there are many
ways to make text in Emacs display something other than its
characters.

I had also written another command using `text-char-description' to
kill text in a lossy way, so that literal characters like ^@ would be
killed as the two characters "^@".  It would also make sense to make
that part of `kill-visible-region', if it's possible.