helix icon indicating copy to clipboard operation
helix copied to clipboard

Marks

Open Omnikar opened this issue 4 years ago • 13 comments

~~Like Vim's m. You can record a mark of the current position of the primary cursor in a register, and it will remember the file, and cursor position. You can then return to the mark later.~~

Revised idea: a mark can store several selections, and returning to the mark will set all selections. As such, mark selections can be passed through operations to alter the selections. This would also mean there can be operations that take as input multiple marks (and/or the current selections).

Omnikar avatar Sep 03 '21 22:09 Omnikar

I wonder if this will intersect with our current m since vim m can take all the keys.

pickfire avatar Sep 07 '21 05:09 pickfire

Kakoune uses z but we have view mode there. https://github.com/mawww/kakoune/blob/master/doc/pages/keys.asciidoc#marks

@oberblastmeister was interested in this, we discussed about storing these as ranges (outside registers) so we can map them through text edits. That way they behave similar to selection ranges and stay in the same place as the document changes. It's a prerequisite for snippet support.

archseer avatar Sep 07 '21 06:09 archseer

I really like the idea(the revised one), and I imagine once this gets implemented, it would be much easier to implement snippet support then. Say we have a snippet: Hello $1, good ${2:morning}! which to give us something like Hello , good morning! We can first select $1(maybe automatically enter edit mode if it does not have a default value). After that user can "jump to the next mark" and have morning selected. A really smooth and unified user experience;)

pppKin avatar Nov 23 '21 03:11 pppKin

Yeah exactly, this was the intent :) It's similar to neovim's proposed extmark except we're using ranges. (Neovim had trouble keeping the marks if there was any edits, which eventually led to me giving up on snippets.nvim and starting work on Helix)

It shouldn't be too hard to do, was thinking we might be able to abstract selections into a type of mark.

archseer avatar Nov 24 '21 00:11 archseer

Maybe this is a stupid question (I have not been following the development of helix until recently), but using marks for snippets wouldn't collide with user-defined marks, would it? Would there be separate concepts of user-defined marks and "other" marks, which would be used for things like snippets (essentially like neovim extmarks), but they would use the same stuff under the hood? Is that an accurate understanding?

pianocomposer321 avatar Dec 07 '21 16:12 pianocomposer321

I imagine they'd be namespaced under and id. "user" vs "snippet" etc

archseer avatar Dec 07 '21 16:12 archseer

So it's not that these will be like vim marks, but also used for snippets etc., but more that they will be like neovim extmarks, and will be used for user-defined marks (similar to vim marks) as well as other things like snippets. Is that right?

pianocomposer321 avatar Dec 07 '21 16:12 pianocomposer321

Yep, exactly.

archseer avatar Dec 08 '21 04:12 archseer

I'm not sure this is a good idea but I think we could re-implement C-i/C-s/C-o as marks commands. The jumplist register would need to be handled uniquely though so it could stack selections.

the-mikedavis avatar Jun 19 '22 17:06 the-mikedavis

I have some prototype working with per-document marks (you can play with it at https://github.com/carrascomj/helix/tree/feat-marks).

It is not a great implementation but the point is that I don't think that working with per-register marks is very user-friendly for the kind of manipulations that I wanted to do (i.e., save selections as marks an then transform them into multi-cursors, join them, etc.). With per-register marks, like in kakoune, it is a bit cumbersome since the user has to always choose a different register after the first mark (if I am doing it right).

In the per-document fashion, I can just have a common list of marks for the current text and save them with a keybind. They are also kept linked to their document when moving to another file, which I think makes sense.

On the other hand, per-document marks do not work at all as actual "bookmarks". Apart from the obvious per-document constraint, the marks are not saved across editing sessions, which is a problem on its own. In addition, the snippet implementation may be more involved if they don't work by registers.

Maybe, it is better to have per-register marks but with a global default mark register which can store n selections (instead of just one). The main problem with this is how to consistently define the behaviours such as when the user copies the cursor back to a mark that is in another document (the user may just lose the selections).

carrascomj avatar Jul 03 '22 21:07 carrascomj

The implementation just seems to recreate a jumplist? It's already possible to explicitly save to it via Ctrl-s.

Markers should be stored on the document level (not the View) and then mapped through changes (just like selections) in apply so the positions get updated through document edits. So rather than JumpList/Jump, it's a Vec<Range> essentially.

Atom has a decent API for it: https://flight-manual.atom.io/api/v1.0.2/Marker/

Represents a buffer annotation that remains logically stationary even as the buffer changes. This is used to represent cursors, folds, snippet targets, misspelled words, and anything else that needs to track a logical location in the buffer over time

Rather than using markers directly on the doc you can also create a MarkerLayer first, to namespace your marks (HashMap<String, Vec<Range>>).

archseer avatar Jul 04 '22 08:07 archseer

Ok, I see. I knew it was already possible to save jumps. I was just experimenting with operations over the marks, like those explained in https://github.com/helix-editor/helix/discussions/2784. I am still studying the codebase so I have a couple questions about a possible Marker API.

Is it required to have a Validity enum attached to each mark (like in Atom)? When calling Document::apply on a Transaction, I believe something very similar to Selection::ensure_variants has to be called for each range in a namespace but I guess extra-handling for Markers is required, such as removing them if needed (?).

On another topic, here, the equivalent to the namespace of the MarkerLayer is also called a "register" in kakoune, but I does not make sense to use a helix_core::Register here. Either way, should the default namespace be called in a particular way (like "@" or "^")?

carrascomj avatar Jul 10 '22 17:07 carrascomj

If anyone's interested, the associated PR is available to be picked up by someone else.

kirawi avatar Apr 02 '24 20:04 kirawi