reddit / emacs
vanish.el: hide parts of a buffer
CoolioDood · 2022-08-06 19:45
CoolioDood · 2022-08-06 19:47
Hi, this is my first 'proper' package. I was working on some Org documents and thought it would be nice to temporarily hide lines defining table formulas (they had gotten quite long and I use text wrap), so I came up with this. It's still quite rough around the edges, but it works for me & I thought someone else might find it useful. Any feedback is welcome (as are PRs)!
[Demo here (also in the README).](https://user-images.githubusercontent.com/8124851/183263651-0ec06d41-53c1-426f-967b-b82d66a99d38.mp4)
shami1kemi1 · 2022-08-06 22:17
So would this basically be reverse narrowing? So instead of showing only the lines/buffer content you want, you instead hide what you don't want to see?
It does look like a neat project though, despite this slight cynicism.
arthurno1 · 2022-08-06 22:34
I took a quick look.
I think the title is slightly misleading. It really should be called: "vanish.el: hide parts of an org buffer" since it is very tightly coupled to outlines in several functions. If you instead used [text properties](https://www.gnu.org/software/emacs/manual/html_node/elisp/Invisible-Text.html), you could have made it to work with any buffer without some significant extra effort.
I suggest turning on warnings :). You have a typo at line 91
;; Set org-cycle-hook
(if hidden
(add-hook 'org-cycle-hook #'vanish--cycle-hook nil 'local)
(remove-hook 'org-cycle-hook #'vanish-cycle-hook 'local)) <-- should be vanish--cycle-hook I guess?
Also consider using checkdoc and [package-lint](https://github.com/purcell/package-lint) before you publish stuff, it is really annoying to get warning pop-up for docs wider than 80 chars. Those are so easy to catch. Generally, it is good to follow [Melpa guidelines](https://github.com/melpa/melpa/blob/master/CONTRIBUTING.org) even if you don't plan to publish your package in Melpa, and even to keep your lines to 80 chars columns.
I like the idea of using a key:
(add-to-list 'vanish-exprs
`(elispcomment . (:key ?c
:name "Elisp comment"
:start ,(rx bol (* blank) ";")
:end ,(rx eol))))
I think it would also be nice to have an interactive "dwim"-style function for marking line, region, element etc. Maybe based on the mode, but it is more work. If you would like to just temporary hide a line or two, or something based on a regex, you probably don't want to defcustom to define all that stuff manually. You could still have it for some more often used stuff, but I would perhaps like to have a buffer-local list of vanish-exprs which would hold some temporary stuff. Just my personal reflection on how I would use it.
Also, remembering which key is bound to which element might be a bit tedious; have you had thought of using completing-read to display hidden elements - since you already have them in a list, and you give them a name, the user can pick from a list of names instead of remembering the key? Also, key shortcuts in Emacs are a scarce resource :).
(defun vanish-hide ()
(interactive)
(let ((elt-name (completing-read "Hide element: " vanish-exprs)))
(vanish-set-hide (intern-soft elt-name) t)))
(defun vanish-unhide ()
(interactive)
(let ((elt-name (completing-read "Unhide element: " vanish--hidden-elements)))
(vanish-set-hide (intern-soft elt-name) nil)))
I have renamed your old vanish-hide to vanish-hide-element in my local code since it works only on a single element at a time. I am using the default for the completing read, since you already have an alist, but you could build a temporary list of names you are storing in element data instead.
But overall, nice idea, so that is why I cloned it and looked at it. I am not really sure if it is generally useful, I think outline mode is probably good enough for the most part, but I don't know, maybe in some cases some like this could be nice to have.
CoolioDood · 2022-08-07 10:06
Thanks for all the feedback, it's very helpful! I have a lot of stuff I can improve.
> it is very tightly coupled to outlines in several functions. If you instead used text properties, you could have made it to work with any buffer without some significant extra effort.
Good point, it's coupled to outline-mode, but I'm not sure if you can have outline-mode without org-mode. I'll take a look at text properties, that might be a better idea.
> I think it would also be nice to have an interactive "dwim"-style function for marking line, region, element etc
Do you mean for hiding e.g. a marked region in the buffer, without the need to define a regex?
CoolioDood · 2022-08-07 10:08
> instead of showing only the lines/buffer content you want, you instead hide what you don't want to see?
Yes, exactly!
arthurno1 · 2022-08-07 11:14
> it's coupled to outline-mode
You have coupled vanish-set-hide, which is your main function to org-mode since you use org-cycle-hook.
> I'm not sure if you can have outline-mode without org-mode.
Of course, you can. Outline mode was its own piece of software, on which org-mode builds and extends it. I recommend you to enable outline mode in elisp-mode or even other prog-modes. It is quite useful.
> Do you mean for hiding e.g. a marked region in the buffer, without the need to define a regex?
Exactly. Consider you have point in a table definition. You can programmatically find which org element you are in, at least for org-mode. Or in a defun for elisp-mode, a sentence or paragraf in plain text and so on. You could just press a shortcut, and based on major-mode you could find boundaries of the element and put it in hidden-list. It would be really fast to work that way. I don't know if it already exists in some package. Or you could go for somewhat easier version, and just check if a region is active, and if it is, hide region, and if not, hide current line, or based on mode, hide element at point. That way we can easily expand/contract region with [er/expand-region](https://github.com/magnars/expand-region.el) and press a key to temporary hide/unhide it. It is not difficult to write a function to do that based on text properties. [Thing-at-point](https://www.gnu.org/software/emacs/manual/html_node/elisp/Buffer-Contents.html) might be useful here too.
organic-bookworm · 2022-08-07 12:54
>I'm not sure if you can have outline-mode without org-mode.
By the way, `org-mode` [discourages](https://github.com/emacs-straight/org-mode/blob/e9da29b6fafe63abbc2774e9d485ac13d2811b65/etc/ORG-NEWS#outline--functions-may-no-longer-work-correctly-in-org-mode) the use of `outline` now, that it has text property-based folding (when that backend is being used).
>From now on, using outline-\* functions is strongly discouraged when working with Org files.
CoolioDood · 2022-08-07 15:53
Interesting. Thanks, all the more reason to move away from outline-mode functions for this.
CoolioDood · 2022-08-07 15:53
> You have coupled vanish-set-hide, which is your main function to org-mode since you use org-cycle-hook.
The reason for that hook is because if you enable vanish-mode in Org, cycling Org visibility with tab will un-hide whatever was hidden with vanish. But it doesn't rely on org-cycle-hook; perhaps I should wrap that in a conditional to only add the hook if Org mode is enabled in the buffer.
I didn't know that about outline-mode, interesting. I only really started using Emacs a year ago so I'm still learning a lot of stuff.
Also - great suggestion, that's the next thing I'll add (right after I remove the dependency on outline-mode).
arthurno1 · 2022-08-07 18:20
If you need some example of using text properties, [here is some of my code](https://github.com/amno1/org-babel-hide-markers-mode), not sure if it is very good example, but it is very short and hopefully easy to understand. [Here is a bit more elaborated one](https://github.com/amno1/org-view-mode), and [here is a bit of unorthodox usage of Emacs](https://github.com/amno1/dired-auto-readme), also using text properties to achieve the effect. I don't recommend anything for "stable" system, beside org-view-mode, rest are just experiments and idea tests.
CoolioDood · 2022-08-07 20:35
Nice, that'll definitely be useful, thank you!
_viz_ · 2022-08-08 10:13
>Also, remembering which key is bound to which element might be a bit tedious; have you had thought of using completing-read to display hidden elements - since you already have them in a list, and you give them a name, the user can pick from a list of names instead of remembering the key? Also, key shortcuts in Emacs are a scarce resource :).
I haven't had a look at the code but read-multiple-choice might be better for this.
arthurno1 · 2022-08-08 10:36
> read-multiple-choice might be better for this
Yes definitely.
github-alphapapa · 2022-08-08 17:14
Cool. Another way to implement it, rather than using toggling commands, would be to use font-locking, which would improve performance in large buffers since it wouldn't be necessary to toggle the whole buffer at once. You can see how I did something similar here: https://github.com/alphapapa/obvious.el