Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Marks #703

Open
Omnikar opened this issue Sep 3, 2021 · 15 comments
Open

Marks #703

Omnikar opened this issue Sep 3, 2021 · 15 comments
Labels
A-core Area: Helix core improvements C-enhancement Category: Improvements

Comments

@Omnikar
Copy link
Contributor

Omnikar commented Sep 3, 2021

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 Omnikar added the C-enhancement Category: Improvements label Sep 3, 2021
@kirawi kirawi added the A-helix-term Area: Helix term improvements label Sep 3, 2021
@archseer archseer added A-core Area: Helix core improvements and removed A-helix-term Area: Helix term improvements labels Sep 4, 2021
@pickfire
Copy link
Contributor

pickfire commented Sep 7, 2021

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

@archseer
Copy link
Member

archseer commented Sep 7, 2021

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.

@pppKin
Copy link
Contributor

pppKin commented Nov 23, 2021

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;)

@archseer
Copy link
Member

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 archseer self-assigned this Nov 24, 2021
@NNBnh NNBnh mentioned this issue Nov 26, 2021
@pianocomposer321
Copy link

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?

@archseer
Copy link
Member

archseer commented Dec 7, 2021

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

@pianocomposer321
Copy link

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?

@archseer
Copy link
Member

archseer commented Dec 8, 2021

Yep, exactly.

@the-mikedavis
Copy link
Member

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.

@carrascomj
Copy link

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).

@archseer
Copy link
Member

archseer commented Jul 4, 2022

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>>).

@carrascomj
Copy link

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 #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 "^")?

@kirawi
Copy link
Member

kirawi commented Apr 2, 2024

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

@the-mikedavis the-mikedavis removed their assignment Apr 2, 2024
@hadronized
Copy link
Contributor

@kirawi I might be interested at some point. Especially, it could be interesting to work on it by also extending hints to allow to extending / adding selections to the current sets of selections.

@dgmulf
Copy link

dgmulf commented Dec 12, 2024

Using marks to create arbitrary selections was a major workflow for me in Kakoune. Consider the following task:

I have some text that I'd like to mark up, say with HTML tags. The specific items that I want to mark up don't follow an exact pattern:

        Link this text, not this text, but this text as well
-->     <a href="url">Link this text</a>, not this text, <a href="url">but this text as well</a>

Unless I'm mistaken, without resorting to an Einstein-level regex or click-and-drag, there's no way to combine all of those selections to reduce the edit to a single pair of insert and append operations (for the opening and closing tags, respectively).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-core Area: Helix core improvements C-enhancement Category: Improvements
Projects
None yet
Development

Successfully merging a pull request may close this issue.

10 participants