atom-archive/text-document

Inserting text in between adjacent markers makes them overlap

mkhl opened this issue · 10 comments

mkhl commented

When we create two adjacent markers and insert text between them, that extends both markers and makes them overlap.

For example, given a buffer

{abc}|{efg}

(where {} denote a marker and | denotes a cursor),
entering d results in

{abc{d|}efg}

with both markers now containing the d character.

I think this is due to the initial situation being indistinguishable from (and being handled as)

{abd{|}def}

in which the markers already overlap, just with no text in between them.

One way to encounter this situation is when expanding a snippet with adjacent placeholders like (in snippet syntax)

${1:one}${2:two}

Replacing one with ab, say, results in these intermediate states (in the notation above):

{a|}{two}
{a{b|}two}

which means jumping to the second tab stop would mark the b we just entered at the first tab stop.

I can see that there's no obvious "correct" approach to take here, so maybe this behaviour is fine? It seems like restriction on the capability of snippets though.

mkhl commented

@lee-dohm This behaviour is the cause of atom/snippets#15, are you sure that feedback is the correct classification?

mkhl commented

Summary

I’ll try to extend Range to indicate whether its ends are open or closed to mitigate this problem.

Context

A Marker marks a buffer range represented by a Range object. A Range is comprised of two Points (row/column pairs) indicating the starting and ending buffer coordinates. Those coordinates are cursor positions, i.e. each denotes a point between two characters in the buffer.

Proposal

I propose extending Range to include information about whether its ends are open or closed, similar to how Ranges are represented in Guava (see also).

Ranges will be closed by default, i.e. without code changes they’ll keep their current behaviour of including (covering) the insertion points at both ends.

This gives packages options to refine which points their markers and ranges include.

Snippets can then create open/closed ranges, i.e. ranges that include the insertion point at the end but not at the start. That should solve atom/snippets#15.

I’ll go ahead and try to implement this. In the meantime I welcome discussion about how we should handle this.

Have you tried the exclusive option that can be passed to set range. We added it a while ago but didn't document it because we were unsure about keeping it. I've decided to just commit to it and document it. It won't allow you to control each endpoint exclusively, but I think it could solve your problem. I'm going to close the issue on that assumption. We can reopen if I'm wrong.

mkhl commented

If I understand exclusive correctly, using it for snippets would create a more severe issue where one can’t append text to markers.

If I insert a snippet ${1:foo} ${2:bar} and type asd, the a would replace foo but the s would, due to exclusive, not be appended to the placeholder. Also because the keystrokes exit the placeholder’s marker I expect that the snippet would be considered finished and that I wouldn’t be able to tab to the next placeholder.

That might be misunderstanding on my part though.

Wouldn't a similar problem apply with a Range that had open endpoints?

mkhl commented

An open Range would be the same as an exclusive Range and would have the same problem.

A left-open Range would exclude the beginning but not the end. It would have different problems (but, in my opinion, fewer and more contrived ones).

mkhl commented

Ideally I’d like if, given a snippet

${1:abc}${2:def}
$2$1

Atom would distinguish the situations where I

  • activate placeholder 1, hit →, enter text (text should appear at the end of line 2)
  • activate placeholder 2, hot ←, enter text (text should appear at the beginning of line 1)

But I don’t think we can do that by extending Range.

@mkhl We could extend the exclusive feature of markers and allow for exclusiveStart/exclusiveEnd or exclusiveHead/exclusiveTail. Putting it on the marker makes more sense to me than putting it on the range, which is a really simple construct and doesn't even encode directionality.

@mkhl I've actually archived this repository because it's not in use. Maybe it would be good to open an issue on snippets describing the surface level problem or an issue on text-buffer proposing the feature. Unfortunately, I can't change course immediately to make this addition, but I do think you raise good points and it would be worthwhile to do once bigger issues are dealt with in our text layer.

All repositories in the atom-archive organization are unmaintained and deprecated. Because of this, we are archiving this repository and closing all issues and pull requests. Thanks very much for your support and contributions!