@@ -498,77 +498,91 @@ impl MultiBuffer {
}
}
- for (buffer_id, mut edits) in buffer_edits {
- edits.sort_unstable_by_key(|edit| edit.range.start);
- self.buffers.borrow()[&buffer_id]
- .buffer
- .update(cx, |buffer, cx| {
- let mut edits = edits.into_iter().peekable();
- let mut insertions = Vec::new();
- let mut original_indent_columns = Vec::new();
- let mut deletions = Vec::new();
- let empty_str: Arc<str> = "".into();
- while let Some(BufferEdit {
- mut range,
- new_text,
- mut is_insertion,
- original_indent_column,
- }) = edits.next()
- {
+ drop(cursor);
+ drop(snapshot);
+ // Non-generic part of edit, hoisted out to avoid blowing up LLVM IR.
+ fn tail(
+ this: &mut MultiBuffer,
+ buffer_edits: HashMap<u64, Vec<BufferEdit>>,
+ autoindent_mode: Option<AutoindentMode>,
+ edited_excerpt_ids: Vec<ExcerptId>,
+ cx: &mut ModelContext<MultiBuffer>,
+ ) {
+ for (buffer_id, mut edits) in buffer_edits {
+ edits.sort_unstable_by_key(|edit| edit.range.start);
+ this.buffers.borrow()[&buffer_id]
+ .buffer
+ .update(cx, |buffer, cx| {
+ let mut edits = edits.into_iter().peekable();
+ let mut insertions = Vec::new();
+ let mut original_indent_columns = Vec::new();
+ let mut deletions = Vec::new();
+ let empty_str: Arc<str> = "".into();
while let Some(BufferEdit {
- range: next_range,
- is_insertion: next_is_insertion,
- ..
- }) = edits.peek()
+ mut range,
+ new_text,
+ mut is_insertion,
+ original_indent_column,
+ }) = edits.next()
{
- if range.end >= next_range.start {
- range.end = cmp::max(next_range.end, range.end);
- is_insertion |= *next_is_insertion;
- edits.next();
- } else {
- break;
+ while let Some(BufferEdit {
+ range: next_range,
+ is_insertion: next_is_insertion,
+ ..
+ }) = edits.peek()
+ {
+ if range.end >= next_range.start {
+ range.end = cmp::max(next_range.end, range.end);
+ is_insertion |= *next_is_insertion;
+ edits.next();
+ } else {
+ break;
+ }
}
- }
- if is_insertion {
- original_indent_columns.push(original_indent_column);
- insertions.push((
- buffer.anchor_before(range.start)..buffer.anchor_before(range.end),
- new_text.clone(),
- ));
- } else if !range.is_empty() {
- deletions.push((
- buffer.anchor_before(range.start)..buffer.anchor_before(range.end),
- empty_str.clone(),
- ));
+ if is_insertion {
+ original_indent_columns.push(original_indent_column);
+ insertions.push((
+ buffer.anchor_before(range.start)
+ ..buffer.anchor_before(range.end),
+ new_text.clone(),
+ ));
+ } else if !range.is_empty() {
+ deletions.push((
+ buffer.anchor_before(range.start)
+ ..buffer.anchor_before(range.end),
+ empty_str.clone(),
+ ));
+ }
}
- }
- let deletion_autoindent_mode =
- if let Some(AutoindentMode::Block { .. }) = autoindent_mode {
- Some(AutoindentMode::Block {
- original_indent_columns: Default::default(),
- })
- } else {
- None
- };
- let insertion_autoindent_mode =
- if let Some(AutoindentMode::Block { .. }) = autoindent_mode {
- Some(AutoindentMode::Block {
- original_indent_columns,
- })
- } else {
- None
- };
+ let deletion_autoindent_mode =
+ if let Some(AutoindentMode::Block { .. }) = autoindent_mode {
+ Some(AutoindentMode::Block {
+ original_indent_columns: Default::default(),
+ })
+ } else {
+ None
+ };
+ let insertion_autoindent_mode =
+ if let Some(AutoindentMode::Block { .. }) = autoindent_mode {
+ Some(AutoindentMode::Block {
+ original_indent_columns,
+ })
+ } else {
+ None
+ };
- buffer.edit(deletions, deletion_autoindent_mode, cx);
- buffer.edit(insertions, insertion_autoindent_mode, cx);
- })
- }
+ buffer.edit(deletions, deletion_autoindent_mode, cx);
+ buffer.edit(insertions, insertion_autoindent_mode, cx);
+ })
+ }
- cx.emit(Event::ExcerptsEdited {
- ids: edited_excerpt_ids,
- });
+ cx.emit(Event::ExcerptsEdited {
+ ids: edited_excerpt_ids,
+ });
+ }
+ tail(self, buffer_edits, autoindent_mode, edited_excerpt_ids, cx);
}
pub fn start_transaction(&mut self, cx: &mut ModelContext<Self>) -> Option<TransactionId> {
@@ -1448,82 +1448,95 @@ impl Buffer {
return None;
}
- self.start_transaction();
- self.pending_autoindent.take();
- let autoindent_request = autoindent_mode
- .and_then(|mode| self.language.as_ref().map(|_| (self.snapshot(), mode)));
-
- let edit_operation = self.text.edit(edits.iter().cloned());
- let edit_id = edit_operation.timestamp();
+ // Non-generic part hoisted out to reduce LLVM IR size.
+ fn tail(
+ this: &mut Buffer,
+ edits: Vec<(Range<usize>, Arc<str>)>,
+ autoindent_mode: Option<AutoindentMode>,
+ cx: &mut ModelContext<Buffer>,
+ ) -> Option<clock::Lamport> {
+ this.start_transaction();
+ this.pending_autoindent.take();
+ let autoindent_request = autoindent_mode
+ .and_then(|mode| this.language.as_ref().map(|_| (this.snapshot(), mode)));
+
+ let edit_operation = this.text.edit(edits.iter().cloned());
+ let edit_id = edit_operation.timestamp();
+
+ if let Some((before_edit, mode)) = autoindent_request {
+ let mut delta = 0isize;
+ let entries = edits
+ .into_iter()
+ .enumerate()
+ .zip(&edit_operation.as_edit().unwrap().new_text)
+ .map(|((ix, (range, _)), new_text)| {
+ let new_text_length = new_text.len();
+ let old_start = range.start.to_point(&before_edit);
+ let new_start = (delta + range.start as isize) as usize;
+ delta +=
+ new_text_length as isize - (range.end as isize - range.start as isize);
+
+ let mut range_of_insertion_to_indent = 0..new_text_length;
+ let mut first_line_is_new = false;
+ let mut original_indent_column = None;
+
+ // When inserting an entire line at the beginning of an existing line,
+ // treat the insertion as new.
+ if new_text.contains('\n')
+ && old_start.column
+ <= before_edit.indent_size_for_line(old_start.row).len
+ {
+ first_line_is_new = true;
+ }
- if let Some((before_edit, mode)) = autoindent_request {
- let mut delta = 0isize;
- let entries = edits
- .into_iter()
- .enumerate()
- .zip(&edit_operation.as_edit().unwrap().new_text)
- .map(|((ix, (range, _)), new_text)| {
- let new_text_length = new_text.len();
- let old_start = range.start.to_point(&before_edit);
- let new_start = (delta + range.start as isize) as usize;
- delta += new_text_length as isize - (range.end as isize - range.start as isize);
-
- let mut range_of_insertion_to_indent = 0..new_text_length;
- let mut first_line_is_new = false;
- let mut original_indent_column = None;
-
- // When inserting an entire line at the beginning of an existing line,
- // treat the insertion as new.
- if new_text.contains('\n')
- && old_start.column <= before_edit.indent_size_for_line(old_start.row).len
- {
- first_line_is_new = true;
- }
+ // When inserting text starting with a newline, avoid auto-indenting the
+ // previous line.
+ if new_text.starts_with('\n') {
+ range_of_insertion_to_indent.start += 1;
+ first_line_is_new = true;
+ }
- // When inserting text starting with a newline, avoid auto-indenting the
- // previous line.
- if new_text.starts_with('\n') {
- range_of_insertion_to_indent.start += 1;
- first_line_is_new = true;
- }
+ // Avoid auto-indenting after the insertion.
+ if let AutoindentMode::Block {
+ original_indent_columns,
+ } = &mode
+ {
+ original_indent_column = Some(
+ original_indent_columns.get(ix).copied().unwrap_or_else(|| {
+ indent_size_for_text(
+ new_text[range_of_insertion_to_indent.clone()].chars(),
+ )
+ .len
+ }),
+ );
+ if new_text[range_of_insertion_to_indent.clone()].ends_with('\n') {
+ range_of_insertion_to_indent.end -= 1;
+ }
+ }
- // Avoid auto-indenting after the insertion.
- if let AutoindentMode::Block {
- original_indent_columns,
- } = &mode
- {
- original_indent_column =
- Some(original_indent_columns.get(ix).copied().unwrap_or_else(|| {
- indent_size_for_text(
- new_text[range_of_insertion_to_indent.clone()].chars(),
- )
- .len
- }));
- if new_text[range_of_insertion_to_indent.clone()].ends_with('\n') {
- range_of_insertion_to_indent.end -= 1;
+ AutoindentRequestEntry {
+ first_line_is_new,
+ original_indent_column,
+ indent_size: before_edit.language_indent_size_at(range.start, cx),
+ range: this
+ .anchor_before(new_start + range_of_insertion_to_indent.start)
+ ..this.anchor_after(new_start + range_of_insertion_to_indent.end),
}
- }
+ })
+ .collect();
- AutoindentRequestEntry {
- first_line_is_new,
- original_indent_column,
- indent_size: before_edit.language_indent_size_at(range.start, cx),
- range: self.anchor_before(new_start + range_of_insertion_to_indent.start)
- ..self.anchor_after(new_start + range_of_insertion_to_indent.end),
- }
- })
- .collect();
+ this.autoindent_requests.push(Arc::new(AutoindentRequest {
+ before_edit,
+ entries,
+ is_block_mode: matches!(mode, AutoindentMode::Block { .. }),
+ }));
+ }
- self.autoindent_requests.push(Arc::new(AutoindentRequest {
- before_edit,
- entries,
- is_block_mode: matches!(mode, AutoindentMode::Block { .. }),
- }));
+ this.end_transaction(cx);
+ this.send_operation(Operation::Buffer(edit_operation), cx);
+ Some(edit_id)
}
-
- self.end_transaction(cx);
- self.send_operation(Operation::Buffer(edit_operation), cx);
- Some(edit_id)
+ tail(self, edits, autoindent_mode, cx)
}
fn did_edit(