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

Give us a way to efficiently work with cursor character positions #88

Open
mcclure opened this issue Nov 15, 2024 · 0 comments
Open

Give us a way to efficiently work with cursor character positions #88

mcclure opened this issue Nov 15, 2024 · 0 comments

Comments

@mcclure
Copy link

mcclure commented Nov 15, 2024

Half a feature request, half a support request.

I am improving the vim compatibility of this library's "vim.rs" example.. So far I've added arrow keys, J, S, r, and R, and I've improved the end-of-line behavior of a and x. I will send a PR soon¹, but I'm hitting a problem:

For a ,x, and R to work properly, they must have different behavior when the cursor is on the final character of the line. I implement this with:

    // True if the textarea cursor is at the end of its given line
    fn is_before_line_end(textarea: &TextArea<'_>) -> bool {
        let (cursor_line, cursor_char) = textarea.cursor();
        let lines = textarea.lines();
        let line = &lines[cursor_line];
        let line_length = line.chars().count(); // FIXME: Not acceptable-- O(N)

        cursor_char < line_length
    }

The problem is that when retrieving the cursor from the library, the offset is in characters², but when accessing the strings in the buffer, you cannot random-access a character index. Your only option is to use the chars() iterator, which will become slow for very long lines.

My proposal is: In addition to .cursor(), offer a .cursor_bytes(), which gives a (line_idx, byte_idx) position instead of (line_idx, char_idx). This would be practical for two reasons:

  1. It would easily, efficiently, and safely solve my problem, because I could compare the cursor_bytes to line_string.len().
  2. If someone was willing to use unsafe {}, I think they could do some string operations more efficiently even when the cursor is not at the end of the line— and despite the use of unsafe {} it would be safe, because we can trust that tui-textarea will only allow the cursor to stop on a unicode character boundary.

However, what is important to me is solving the problem, there may be other proposals that solve it in a different or better way. What do you think?


¹ The added characters in my patch work correctly in normal mode, but still have some FIXMEs when pressed in visual mode; they do not do the same thing in that case as standard vim.

² This is what the documentation says, and what my testing with multibyte characters confirms 👍, but by the way, can you confirm that the cursor() character index really is chars, not graphemes?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant