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

Incorrect auto pair at line ending #1436

Closed
CptPotato opened this issue Jan 4, 2022 · 8 comments · Fixed by #1470
Closed

Incorrect auto pair at line ending #1436

CptPotato opened this issue Jan 4, 2022 · 8 comments · Fixed by #1470
Labels
A-core Area: Helix core improvements C-bug Category: This is a bug

Comments

@CptPotato
Copy link
Contributor

CptPotato commented Jan 4, 2022

Auto paring of quotes and braces appears to break when the cursor is at the end of a line.

The exact behaviour is not clear to me but here are some notes using braces as an example:

  • the issue only occurs if the cursor is at the line ending
  • if I open a new document and insert (, the cursor is not inside the braces
    • the result is ()▏ instead of (▏)
    • the braces also get added to the selection
  • if I exit and re-enter insert mode the braces get completed normally but the closing brace is added to the selection
helix.mp4

I guess this has something to do with the line endings breaking but I don't know enough about helix' internals to be sure.

(On a side note, if I set the line endings to lf and then back to crlf helix now reports the line ending as carriage return instead of crlf.)

Environment

  • Platform: Win10 x64
  • Helix version: v0.5.0-342-gbd0d20a compiled from source, also present in 0.6.0 github release
@CptPotato CptPotato added the C-bug Category: This is a bug label Jan 4, 2022
@CptPotato
Copy link
Contributor Author

Looks like this behaviour started with #1254

@archseer
Copy link
Member

archseer commented Jan 4, 2022

\cc @dead10ck

@dead10ck
Copy link
Member

dead10ck commented Jan 4, 2022

Very strange, this must be a platform specific issue. Does this still happen if you set line endings to just lf?

@CptPotato
Copy link
Contributor Author

Very strange, this must be a platform specific issue. Does this still happen if you set line endings to just lf?

Yes, setting line endings to lf has the same effect. I'll try to reproduce it on my linux machine later.

@dead10ck
Copy link
Member

dead10ck commented Jan 4, 2022

Interesting, and setting to crlf on Linux did not reproduce for me. I'll dig into this later tonight.

@kirawi kirawi added A-helix-term Area: Helix term improvements A-core Area: Helix core improvements and removed A-helix-term Area: Helix term improvements labels Jan 4, 2022
@dead10ck
Copy link
Member

dead10ck commented Jan 4, 2022

@CptPotato in the meantime, would you be able to generate some debug logs for me? Could you clear any current logs you might have and then:

  1. run hx -vvv
  2. press i to enter insert mode
  3. Press ( to trigger a pair
  4. Press esc and :qa!

Then save this log by itself, clear the standard log file again and do:

  1. Run hx -vvv
  2. Press i to enter insert mode and insert a single space, then esc
  3. Move cursor one to the left so it sits on the whitespace
  4. Hit a to append
  5. Hit ( to trigger a pair
  6. Esc and :qa!

Then save this log by itself.

These logs will help me dig into it. Thanks!

@CptPotato
Copy link
Contributor Author

CptPotato commented Jan 4, 2022

I haven't tried your instructions, yet, but it definitely seems like it's the line endings. Maybe helix uses the OS specific line endings in some parts of it's code regardless of the setting. Another possibility is that mixed line endings or ones that differ from the setting break helix when they're encountered / parsed.

I can reproduce the bug on linux if I open a file with crlf as new lines.

For example with python:

f = open("test.txt", "wb")
f.write(b"\x0A\x0D") # CR, LF
f.close()

test.txt


edit: here are the logs:

helix.log
2022-01-04T20:18:28.860 helix_core::auto_pairs [DEBUG] autopairs hook selection: Selection {
    ranges: [
        Range {
            anchor: 0,
            head: 2,
            horiz: None,
        },
    ],
    primary_index: 0,
}
2022-01-04T20:18:28.863 helix_core::auto_pairs [DEBUG] auto pair transaction: Transaction {
    changes: ChangeSet {
        changes: [
            Insert(
                Tendril<UTF8>(inline: "()"),
            ),
            Retain(
                2,
            ),
        ],
        len: 2,
        len_after: 4,
    },
    selection: Some(
        Selection {
            ranges: [
                Range {
                    anchor: 0,
                    head: 3,
                    horiz: None,
                },
            ],
            primary_index: 0,
        },
    ),
}
helix.log (with space)
2022-01-04T20:19:01.693 helix_core::auto_pairs [DEBUG] autopairs hook selection: Selection {
    ranges: [
        Range {
            anchor: 0,
            head: 2,
            horiz: None,
        },
    ],
    primary_index: 0,
}
2022-01-04T20:19:14.112 helix_core::auto_pairs [DEBUG] autopairs hook selection: Selection {
    ranges: [
        Range {
            anchor: 0,
            head: 3,
            horiz: None,
        },
    ],
    primary_index: 0,
}
2022-01-04T20:19:14.112 helix_core::auto_pairs [DEBUG] auto pair transaction: Transaction {
    changes: ChangeSet {
        changes: [
            Retain(
                1,
            ),
            Insert(
                Tendril<UTF8>(inline: "()"),
            ),
            Retain(
                2,
            ),
        ],
        len: 3,
        len_after: 5,
    },
    selection: Some(
        Selection {
            ranges: [
                Range {
                    anchor: 0,
                    head: 4,
                    horiz: None,
                },
            ],
            primary_index: 0,
        },
    ),
}

@dead10ck
Copy link
Member

dead10ck commented Jan 5, 2022

Ah, I see the problem. It's here:

let end_anchor = match (start_range.len(), start_range.direction()) {
// if we have a zero width cursor, it shifts to the same number
(0, _) => end_head,
// if we are inserting for a regular one-width cursor, the anchor
// moves with the head
(1, Direction::Forward) => end_head - 1,
(1, Direction::Backward) => end_head + 1,
// if we are appending, the anchor stays where it is; only offset
// for multiple range insertions
(_, Direction::Forward) => start_range.anchor + offset,
// when we are inserting in front of a selection, we need to move
// the anchor over by however many characters were inserted overall
(_, Direction::Backward) => start_range.anchor + offset + len_inserted,
};

We check if the selection is a single-width cursor by checking if the length of the range is 1; for CRLF, it's actually 2. So it thinks there is a multi-character selection when there is not. Strangely, for me, I did not run into the cursor advancing past the end of the paren, but I did see the selection ending up incorrect.

I think what we need to do is check if the number of graphemes in the range is 1 to get the correct behavior. I'll try to fix this soon.

Additionally, I noticed from @CptPotato 's logs that the range was actually in the forward direction, when it should have been backward for an insert. I confirmed that when you first open helix and immediately go to insert mode, the range is [0, 1). If you then delete anything you enter and go to insert mode again, in the same empty document, it's [1, 0) as it should be. I would expect this to lead to the behavior of extending the selection, since it's both a 2-code point line ending and in the forward direction. This seems like an unrelated bug.

dead10ck added a commit to dead10ck/helix that referenced this issue Jan 10, 2022
Auto pairs were resulting in incorrect ranges in the resulting selections
when the line terminators are CRLF (i.e. Windows). It turns out this is
because when we were checking if the selection was a single-width cursor,
it incorrectly assumed that this would be a single char. This is not
the case, as a cursor can cover a multi-code point grapheme. Therefore,
we must instead explicitly work with and check graphemes to determine
if the cursor should move or extend the selection.

Fixes helix-editor#1436
dead10ck added a commit to dead10ck/helix that referenced this issue Jan 10, 2022
Auto pairs were resulting in incorrect ranges in the resulting when the
line terminators are CRLF (i.e. Windows). It turns out this is because
when we were checking if the selection was a single-width cursor, it
incorrectly assumed that this would be a single char. This is not the
case, as a cursor can cover a multi-code point grapheme. Therefore,
we must instead explicitly work with and check graphemes to determine
if the cursor should move or extend the selection.

Fixes helix-editor#1436
dead10ck added a commit to dead10ck/helix that referenced this issue Jan 10, 2022
Auto pairs were resulting in incorrect ranges in the resulting when the
line terminators are CRLF (i.e. Windows). It turns out this is because
when we were checking if the selection was a single-width cursor, it
incorrectly assumed that this would be a single char. This is not the
case, as a cursor can cover a multi-code point grapheme. Therefore,
we must instead explicitly work with and check graphemes to determine
if the cursor should move or extend the selection.

Fixes helix-editor#1436
dead10ck added a commit to dead10ck/helix that referenced this issue Jan 16, 2022
Auto pairs were resulting in incorrect ranges in the resulting when the
line terminators are CRLF (i.e. Windows). It turns out this is because
when we were checking if the selection was a single-width cursor, it
incorrectly assumed that this would be a single char. This is not the
case, as a cursor can cover a multi-code point grapheme. Therefore,
we must instead explicitly work with and check graphemes to determine
if the cursor should move or extend the selection.

Fixes helix-editor#1436
archseer pushed a commit that referenced this issue Jan 17, 2022
Auto pairs were resulting in incorrect ranges in the resulting when the
line terminators are CRLF (i.e. Windows). It turns out this is because
when we were checking if the selection was a single-width cursor, it
incorrectly assumed that this would be a single char. This is not the
case, as a cursor can cover a multi-code point grapheme. Therefore,
we must instead explicitly work with and check graphemes to determine
if the cursor should move or extend the selection.

Fixes #1436
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-bug Category: This is a bug
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants