Optimize rendering by using Ropey::byte_slice

This avoids costly conversions via byte_to_char (which are then
reversed back into bytes internally in Ropey).

Reduces time spent in slice/byte_to_char from ~24% to ~5%.
pull/1826/head
Blaž Hrastnik 3 years ago
parent c6bd105484
commit 59f05088b9
No known key found for this signature in database
GPG Key ID: 1238B9C4AD889640

10
Cargo.lock generated

@ -862,10 +862,10 @@ checksum = "8c31b5c4033f8fdde8700e4657be2c497e7288f01515be52168c631e2e4d4086"
[[package]] [[package]]
name = "ropey" name = "ropey"
version = "1.3.2" version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "git+https://github.com/cessen/ropey#38531e083f8cf5c5b1aeb328361895fb5a9b867c"
checksum = "e6b9aa65bcd9f308d37c7158b4a1afaaa32b8450213e20c9b98e7d5b3cc2fec3"
dependencies = [ dependencies = [
"smallvec", "smallvec",
"str_indices",
] ]
[[package]] [[package]]
@ -1031,6 +1031,12 @@ version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d44a3643b4ff9caf57abcee9c2c621d6c03d9135e0d8b589bd9afb5992cb176a" checksum = "d44a3643b4ff9caf57abcee9c2c621d6c03d9135e0d8b589bd9afb5992cb176a"
[[package]]
name = "str_indices"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "283baa48c486e4c5e27b4d92c435db9eaceac236a74dab5e3293570e2c3fa4aa"
[[package]] [[package]]
name = "syn" name = "syn"
version = "1.0.88" version = "1.0.88"

@ -15,7 +15,8 @@ include = ["src/**/*", "README.md"]
[dependencies] [dependencies]
helix-loader = { version = "0.6", path = "../helix-loader" } helix-loader = { version = "0.6", path = "../helix-loader" }
ropey = "1.3" # ropey = "1.3"
ropey = { git = "https://github.com/cessen/ropey" }
smallvec = "1.8" smallvec = "1.8"
smartstring = "1.0.0" smartstring = "1.0.0"
unicode-segmentation = "1.9" unicode-segmentation = "1.9"

@ -333,10 +333,7 @@ impl<'a> Iterator for RopeGraphemes<'a> {
} }
if a < self.cur_chunk_start { if a < self.cur_chunk_start {
let a_char = self.text.byte_to_char(a); Some(self.text.byte_slice(a..b))
let b_char = self.text.byte_to_char(b);
Some(self.text.slice(a_char..b_char))
} else { } else {
let a2 = a - self.cur_chunk_start; let a2 = a - self.cur_chunk_start;
let b2 = b - self.cur_chunk_start; let b2 = b - self.cur_chunk_start;

@ -576,9 +576,7 @@ pub struct Syntax {
} }
fn byte_range_to_str(range: std::ops::Range<usize>, source: RopeSlice) -> Cow<str> { fn byte_range_to_str(range: std::ops::Range<usize>, source: RopeSlice) -> Cow<str> {
let start_char = source.byte_to_char(range.start); Cow::from(source.byte_slice(range))
let end_char = source.byte_to_char(range.end);
Cow::from(source.slice(start_char..end_char))
} }
impl Syntax { impl Syntax {
@ -1197,9 +1195,7 @@ impl<'a> TextProvider<'a> for RopeProvider<'a> {
type I = ChunksBytes<'a>; type I = ChunksBytes<'a>;
fn text(&mut self, node: Node) -> Self::I { fn text(&mut self, node: Node) -> Self::I {
let start_char = self.0.byte_to_char(node.start_byte()); let fragment = self.0.byte_slice(node.start_byte()..node.end_byte());
let end_char = self.0.byte_to_char(node.end_byte());
let fragment = self.0.slice(start_char..end_char);
ChunksBytes { ChunksBytes {
chunks: fragment.chunks(), chunks: fragment.chunks(),
} }

@ -183,6 +183,7 @@ impl EditorView {
.highlight_iter(text.slice(..), Some(range), None) .highlight_iter(text.slice(..), Some(range), None)
.map(|event| event.unwrap()) .map(|event| event.unwrap())
.map(move |event| match event { .map(move |event| match event {
// TODO: use byte slices directly
// convert byte offsets to char offset // convert byte offsets to char offset
HighlightEvent::Source { start, end } => { HighlightEvent::Source { start, end } => {
let start = let start =
@ -317,6 +318,8 @@ impl EditorView {
theme: &Theme, theme: &Theme,
highlights: H, highlights: H,
) { ) {
// It's slightly more efficient to produce a full RopeSlice from the Rope, then slice that a bunch
// of times than it is to always call Rope::slice/get_slice (it will internally always hit RSEnum::Light).
let text = doc.text().slice(..); let text = doc.text().slice(..);
let mut spans = Vec::new(); let mut spans = Vec::new();
@ -327,10 +330,6 @@ impl EditorView {
let text_style = theme.get("ui.text"); let text_style = theme.get("ui.text");
// It's slightly more efficient to produce a full RopeSlice from the Rope, then slice that a bunch
// of times than it is to always call Rope::slice/get_slice (it will internally always hit RSEnum::Light).
let text = text.slice(..);
'outer: for event in highlights { 'outer: for event in highlights {
match event { match event {
HighlightEvent::HighlightStart(span) => { HighlightEvent::HighlightStart(span) => {

Loading…
Cancel
Save