editor: Improve range_to_utf16 and range_from_utf16 by use Rope. (#1268)

Now, we can work on 200K lines (editing).

--------

Now, all cost are on tree-sitter parse.

<img width="1091" height="672" alt="image"
src="https://github.com/user-attachments/assets/b111bc58-1334-40b2-9920-7006ad86bb3c"
/>
This commit is contained in:
Jason Lee 2025-09-22 14:07:30 +08:00 committed by GitHub
parent 692057f799
commit aa0f6d6222
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 14 additions and 31 deletions

View file

@ -15,7 +15,8 @@ UI components for building fantastic desktop applications using [GPUI](https://g
- **High Performance**: Virtualized Table and List components for smooth large-data rendering.
- **Content Rendering**: Native support for Markdown and simple HTML.
- **Charting**: Built-in charts for visualization your data.
- **Code Highlighting**: Code Editor and Syntax highlighting.
- **Editor**: High performance code editor (support up to 200K lines) with LSP (diagnostics, completion, hover, etc).
- **Syntax Highlighting**: Syntax highlighting for editor and markdown components using Tree Sitter.
- **Wef**: (Experimental) Offscreen rendering webview based on [CEF](https://github.com/chromiumembedded/cef).
## Showcase
@ -87,7 +88,7 @@ Check out [CONTRIBUTING.md](CONTRIBUTING.md) for more details.
| Syntax Highlight | [Tree Sitter] | [Syntect] | [Syntect] | [QSyntaxHighlighter] |
| Markdown Rendering | Yes | Yes | Basic | No |
| Markdown mix HTML | Yes | No | No | No |
| HTML Rendering | Basic | No | No | Basic |
| HTML Rendering | Basic | No | No | Basic |
| Text Selection | TextView | No | Any Label | No |
| Themes | Yes | No | No | No |
| I18n | Yes | Yes | Yes | Yes |

View file

@ -200,12 +200,12 @@ impl CompletionProvider for ExampleLspStore {
return Task::ready(Ok(vec![]));
}
let _ = rope.to_string(); // Just to use the rope parameter.
let pos = rope.offset_to_position(offset);
// Simulate to delay for fetching completions
let rope = rope.clone();
let items = self.completions.clone();
cx.background_spawn(async move {
let pos = rope.offset_to_position(offset);
// Simulate a slow completion source, to test Editor async handling.
smol::Timer::after(Duration::from_millis(20)).await;
@ -940,7 +940,7 @@ fn main() {
cx.activate(true);
story::create_new_window_with_size(
"Code Editor",
"Editor",
Some(size(px(1200.), px(960.))),
|window, cx| cx.new(|cx| Example::new(name, window, cx)),
cx,

View file

@ -11,7 +11,7 @@ use gpui::{
ScrollWheelEvent, SharedString, Styled as _, Subscription, Task, UTF16Selection, Window,
WrappedLine,
};
use rope::Rope;
use rope::{OffsetUtf16, Rope};
use serde::Deserialize;
use smallvec::SmallVec;
use std::cell::RefCell;
@ -1968,40 +1968,22 @@ impl InputState {
cx.notify()
}
#[inline]
pub(super) fn offset_from_utf16(&self, offset: usize) -> usize {
let mut utf8_offset = 0;
let mut utf16_count = 0;
for ch in self.text.chars() {
if utf16_count >= offset {
break;
}
utf16_count += ch.len_utf16();
utf8_offset += ch.len_utf8();
}
utf8_offset
self.text.offset_utf16_to_offset(OffsetUtf16(offset))
}
#[inline]
pub(super) fn offset_to_utf16(&self, offset: usize) -> usize {
let mut utf16_offset = 0;
let mut utf8_count = 0;
for ch in self.text.chars() {
if utf8_count >= offset {
break;
}
utf8_count += ch.len_utf8();
utf16_offset += ch.len_utf16();
}
utf16_offset
self.text.offset_to_offset_utf16(offset).0
}
#[inline]
pub(super) fn range_to_utf16(&self, range: &Range<usize>) -> Range<usize> {
self.offset_to_utf16(range.start)..self.offset_to_utf16(range.end)
}
#[inline]
pub(super) fn range_from_utf16(&self, range_utf16: &Range<usize>) -> Range<usize> {
self.offset_from_utf16(range_utf16.start)..self.offset_from_utf16(range_utf16.end)
}