Avoid copying fragments (#3136)

* Avoid copying fragments

* Add slice / slices method

* Better documentation for fragment and slice methods
pull/3327/head
Matthias Deiml 2 years ago committed by GitHub
parent afd292e3b9
commit 0ee2061102
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -222,9 +222,23 @@ impl Range {
// groupAt // groupAt
/// Returns the text inside this range given the text of the whole buffer.
///
/// The returned `Cow` is a reference if the range of text is inside a single
/// chunk of the rope. Otherwise a copy of the text is returned. Consider
/// using `slice` instead if you do not need a `Cow` or `String` to avoid copying.
#[inline] #[inline]
pub fn fragment<'a, 'b: 'a>(&'a self, text: RopeSlice<'b>) -> Cow<'b, str> { pub fn fragment<'a, 'b: 'a>(&'a self, text: RopeSlice<'b>) -> Cow<'b, str> {
text.slice(self.from()..self.to()).into() self.slice(text).into()
}
/// Returns the text inside this range given the text of the whole buffer.
///
/// The returned value is a reference to the passed slice. This method never
/// copies any contents.
#[inline]
pub fn slice<'a, 'b: 'a>(&'a self, text: RopeSlice<'b>) -> RopeSlice<'b> {
text.slice(self.from()..self.to())
} }
//-------------------------------- //--------------------------------
@ -548,6 +562,10 @@ impl Selection {
self.ranges.iter().map(move |range| range.fragment(text)) self.ranges.iter().map(move |range| range.fragment(text))
} }
pub fn slices<'a>(&'a self, text: RopeSlice<'a>) -> impl Iterator<Item = RopeSlice> + 'a {
self.ranges.iter().map(move |range| range.slice(text))
}
#[inline(always)] #[inline(always)]
pub fn iter(&self) -> std::slice::Iter<'_, Range> { pub fn iter(&self) -> std::slice::Iter<'_, Range> {
self.ranges.iter() self.ranges.iter()

@ -766,7 +766,7 @@ fn trim_selections(cx: &mut Context) {
.selection(view.id) .selection(view.id)
.iter() .iter()
.filter_map(|range| { .filter_map(|range| {
if range.is_empty() || range.fragment(text).chars().all(|ch| ch.is_whitespace()) { if range.is_empty() || range.slice(text).chars().all(|ch| ch.is_whitespace()) {
return None; return None;
} }
let mut start = range.from(); let mut start = range.from();
@ -1289,12 +1289,12 @@ fn replace(cx: &mut Context) {
fn switch_case_impl<F>(cx: &mut Context, change_fn: F) fn switch_case_impl<F>(cx: &mut Context, change_fn: F)
where where
F: Fn(Cow<str>) -> Tendril, F: Fn(RopeSlice) -> Tendril,
{ {
let (view, doc) = current!(cx.editor); let (view, doc) = current!(cx.editor);
let selection = doc.selection(view.id); let selection = doc.selection(view.id);
let transaction = Transaction::change_by_selection(doc.text(), selection, |range| { let transaction = Transaction::change_by_selection(doc.text(), selection, |range| {
let text: Tendril = change_fn(range.fragment(doc.text().slice(..))); let text: Tendril = change_fn(range.slice(doc.text().slice(..)));
(range.from(), range.to(), Some(text)) (range.from(), range.to(), Some(text))
}); });
@ -1320,11 +1320,15 @@ fn switch_case(cx: &mut Context) {
} }
fn switch_to_uppercase(cx: &mut Context) { fn switch_to_uppercase(cx: &mut Context) {
switch_case_impl(cx, |string| string.to_uppercase().into()); switch_case_impl(cx, |string| {
string.chunks().map(|chunk| chunk.to_uppercase()).collect()
});
} }
fn switch_to_lowercase(cx: &mut Context) { fn switch_to_lowercase(cx: &mut Context) {
switch_case_impl(cx, |string| string.to_lowercase().into()); switch_case_impl(cx, |string| {
string.chunks().map(|chunk| chunk.to_lowercase()).collect()
});
} }
pub fn scroll(cx: &mut Context, offset: usize, direction: Direction) { pub fn scroll(cx: &mut Context, offset: usize, direction: Direction) {
@ -3903,8 +3907,8 @@ fn rotate_selection_contents(cx: &mut Context, direction: Direction) {
let selection = doc.selection(view.id); let selection = doc.selection(view.id);
let mut fragments: Vec<_> = selection let mut fragments: Vec<_> = selection
.fragments(text) .slices(text)
.map(|fragment| Tendril::from(fragment.as_ref())) .map(|fragment| fragment.chunks().collect())
.collect(); .collect();
let group = count let group = count
@ -4510,8 +4514,8 @@ fn shell_keep_pipe(cx: &mut Context) {
let text = doc.text().slice(..); let text = doc.text().slice(..);
for (i, range) in selection.ranges().iter().enumerate() { for (i, range) in selection.ranges().iter().enumerate() {
let fragment = range.fragment(text); let fragment = range.slice(text);
let (_output, success) = match shell_impl(shell, input, Some(fragment.as_bytes())) { let (_output, success) = match shell_impl(shell, input, Some(fragment)) {
Ok(result) => result, Ok(result) => result,
Err(err) => { Err(err) => {
cx.editor.set_error(err.to_string()); cx.editor.set_error(err.to_string());
@ -4542,7 +4546,7 @@ fn shell_keep_pipe(cx: &mut Context) {
fn shell_impl( fn shell_impl(
shell: &[String], shell: &[String],
cmd: &str, cmd: &str,
input: Option<&[u8]>, input: Option<RopeSlice>,
) -> anyhow::Result<(Tendril, bool)> { ) -> anyhow::Result<(Tendril, bool)> {
use std::io::Write; use std::io::Write;
use std::process::{Command, Stdio}; use std::process::{Command, Stdio};
@ -4564,7 +4568,9 @@ fn shell_impl(
}; };
if let Some(input) = input { if let Some(input) = input {
let mut stdin = process.stdin.take().unwrap(); let mut stdin = process.stdin.take().unwrap();
stdin.write_all(input)?; for chunk in input.chunks() {
stdin.write_all(chunk.as_bytes())?;
}
} }
let output = process.wait_with_output()?; let output = process.wait_with_output()?;
@ -4593,8 +4599,8 @@ fn shell(cx: &mut compositor::Context, cmd: &str, behavior: &ShellBehavior) {
let text = doc.text().slice(..); let text = doc.text().slice(..);
for range in selection.ranges() { for range in selection.ranges() {
let fragment = range.fragment(text); let fragment = range.slice(text);
let (output, success) = match shell_impl(shell, cmd, pipe.then(|| fragment.as_bytes())) { let (output, success) = match shell_impl(shell, cmd, pipe.then(|| fragment)) {
Ok(result) => result, Ok(result) => result,
Err(err) => { Err(err) => {
cx.editor.set_error(err.to_string()); cx.editor.set_error(err.to_string());

@ -1291,8 +1291,8 @@ fn sort_impl(
let selection = doc.selection(view.id); let selection = doc.selection(view.id);
let mut fragments: Vec<_> = selection let mut fragments: Vec<_> = selection
.fragments(text) .slices(text)
.map(|fragment| Tendril::from(fragment.as_ref())) .map(|fragment| fragment.chunks().collect())
.collect(); .collect();
fragments.sort_by(match reverse { fragments.sort_by(match reverse {

@ -1029,8 +1029,8 @@ impl EditorView {
if doc if doc
.selection(view.id) .selection(view.id)
.primary() .primary()
.fragment(doc.text().slice(..)) .slice(doc.text().slice(..))
.width() .len_chars()
<= 1 <= 1
{ {
return EventResult::Ignored(None); return EventResult::Ignored(None);

Loading…
Cancel
Save