reddit / emacs
How to pin/lock/fix text
MonsieurPi · 2022-08-01 10:10
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.
```elisp
(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))))
```
_viz_ · 2022-08-01 12:33
You could use the header-line and call it a day.
github-alphapapa · 2022-08-01 14:49
AFAIK there are some packages that do something similar to this, for various purposes. You could look at their code. Basically, you need to update the position of the overlay using, e.g. `window-start` every time the user scrolls.
MonsieurPi · 2022-08-01 14:51
Oh, that's nice. I'll look into it and come back to you if I have any problem if you don't mind :-)
github-alphapapa · 2022-08-01 14:57
Don't wait for an answer if you do. I have a lot of projects and not much time for them, so fixing other people's source code is really low on my list, unless you want to hire me to do some 1-on-1 tutoring. I hope you'll understand.
MonsieurPi · 2022-08-01 14:59
I understand for sure! Don't worry and have fun in your projects ;-) Thanks for the idea, it'll help me a lot
MonsieurPi · 2022-08-01 16:50
Sadly, moving the overlay will move the overlay but not the selection it is applied to. Do you know some packages that do so so I can check how they achieve it?
00-11 · 2022-08-01 16:54
https://stackoverflow.com/q/73174785/729907
MonsieurPi · 2022-08-01 16:55
Yep, i cross-posted ;-)
Phil-Hudson · 2022-08-01 19:45
You could do what Excel does: create a cloned buffer. Set `window-min-height` to 1, `M-x clone-indirect-buffer-other-window` (`C-x 4 c`), scroll to the text to be "pinned", `M-x shrink-window`, `M-x repeat` (`C-x z z z ...`), `M-x other-window` (`C-x o`), and on you go. Put these steps into a keyboard macro or a command `defun` for easy re-use.
Edit: further steps, corrected clone command keybind
MonsieurPi · 2022-08-01 19:49
Yep, that's what I thought but without knowing what functions to use!, thanks for confirming what I was going to do is not stupid :-)
I hoped I could achieve it with overlays but it seems impossible.
Thanks for your answer :-)
Phil-Hudson · 2022-08-01 19:54
Note edits
MonsieurPi · 2022-08-01 19:57
Noted, thanks ;-)
MonsieurPi · 2022-08-01 22:31
Thanks to u/Phil-Hudson I managed to have something that works well for me:
(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.
[deleted] · 2022-08-01 22:35
[deleted]
_viz_ · 2022-08-02 05:12
You might want to set the no-other-window window parameter.
github-alphapapa · 2022-08-06 02:01
> Sadly, moving the overlay will move the overlay but not the selection it is applied to
I don't understand what you mean.
> Do you know some packages that do so so I can check how they achieve it?
I don't recall any, but there are probably some out there.
MonsieurPi · 2022-08-06 07:03
I didn't manage to move the selection with the overlay.
Let's say I have the following text
line 1
line 2
<m>line 3<p>
with `<m>` and `<p>` being the mark and the point. My initial overlay will be on line 3 and if, for example, I give it the attribue `invisible` my text will look like this:
line 1
line 2
<p>
If I move the overlay to the top of the window before making it invisible, it will look like this:
line 2
line 3<p>
My overlay moved to the top but not the selection it was applied to.
What I wanted to have is:
<m>line 3<p>
line 1
line 2
MonsieurPi · 2022-08-06 07:22
Thanks for the tip. I'm not sure I'll want to use it but now I know at least that it exists :-)
github-alphapapa · 2022-08-08 17:03
Friendly correction: in Emacs, what you call the *selection* is called the *region*. :)
What you're talking about would seem to involve modifying the buffer text. But that's probably not what you really want to do. Instead, you probably want to give the overlay a `display` or `before-string` property to cause the given text to display where the overlay is. I recommend consulting the Elisp manual about overlays and properties.