Add a command to expand the context for a multibuffer (#10300)
This PR adds an action to expand the excerpts lines of context in a
multibuffer.
Release Notes:
- Added an `editor::ExpandExcerpts` action (bound to `shift-enter` by
default), which can expand the excerpt the cursor is currently in by 3
lines. You can customize the number of lines by rebinding this action
like so:
```json5
// In your keybindings array...
{
"context": "Editor && mode == full",
"bindings": {
"shift-enter": ["editor::ExpandExcerpts", { "lines": 5 }],
}
}
```
---------
Co-authored-by: Nathan <nathan@zed.dev>
Co-authored-by: Max <max@zed.dev>
This commit is contained in:
parent
9d9bce08a7
commit
8a02159b82
14 changed files with 353 additions and 45 deletions
|
|
@ -94,12 +94,19 @@ pub struct SelectDownByLines {
|
|||
pub(super) lines: u32,
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Clone, Deserialize, Default)]
|
||||
pub struct ExpandExcerpts {
|
||||
#[serde(default)]
|
||||
pub(super) lines: u32,
|
||||
}
|
||||
|
||||
impl_actions!(
|
||||
editor,
|
||||
[
|
||||
SelectNext,
|
||||
SelectPrevious,
|
||||
SelectToBeginningOfLine,
|
||||
ExpandExcerpts,
|
||||
MovePageUp,
|
||||
MovePageDown,
|
||||
SelectToEndOfLine,
|
||||
|
|
@ -254,6 +261,6 @@ gpui::actions!(
|
|||
UndoSelection,
|
||||
UnfoldLines,
|
||||
UniqueLinesCaseSensitive,
|
||||
UniqueLinesCaseInsensitive
|
||||
UniqueLinesCaseInsensitive,
|
||||
]
|
||||
);
|
||||
|
|
|
|||
|
|
@ -7462,6 +7462,28 @@ impl Editor {
|
|||
self.selection_history.mode = SelectionHistoryMode::Normal;
|
||||
}
|
||||
|
||||
pub fn expand_excerpts(&mut self, action: &ExpandExcerpts, cx: &mut ViewContext<Self>) {
|
||||
let selections = self.selections.disjoint_anchors();
|
||||
|
||||
let lines = if action.lines == 0 { 3 } else { action.lines };
|
||||
|
||||
self.buffer.update(cx, |buffer, cx| {
|
||||
buffer.expand_excerpts(
|
||||
selections
|
||||
.into_iter()
|
||||
.map(|selection| selection.head().excerpt_id)
|
||||
.dedup(),
|
||||
lines,
|
||||
cx,
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn expand_excerpt(&mut self, excerpt: ExcerptId, cx: &mut ViewContext<Self>) {
|
||||
self.buffer
|
||||
.update(cx, |buffer, cx| buffer.expand_excerpts([excerpt], 3, cx))
|
||||
}
|
||||
|
||||
fn go_to_diagnostic(&mut self, _: &GoToDiagnostic, cx: &mut ViewContext<Self>) {
|
||||
self.go_to_diagnostic_impl(Direction::Next, cx)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,9 +13,9 @@ use crate::{
|
|||
mouse_context_menu::{self, MouseContextMenu},
|
||||
scroll::scroll_amount::ScrollAmount,
|
||||
CursorShape, DisplayPoint, DocumentHighlightRead, DocumentHighlightWrite, Editor, EditorMode,
|
||||
EditorSettings, EditorSnapshot, EditorStyle, GutterDimensions, HalfPageDown, HalfPageUp,
|
||||
HoveredCursor, LineDown, LineUp, OpenExcerpts, PageDown, PageUp, Point, SelectPhase, Selection,
|
||||
SoftWrap, ToPoint, CURSORS_VISIBLE_FOR, MAX_LINE_LEN,
|
||||
EditorSettings, EditorSnapshot, EditorStyle, ExpandExcerpts, GutterDimensions, HalfPageDown,
|
||||
HalfPageUp, HoveredCursor, LineDown, LineUp, OpenExcerpts, PageDown, PageUp, Point,
|
||||
SelectPhase, Selection, SoftWrap, ToPoint, CURSORS_VISIBLE_FOR, MAX_LINE_LEN,
|
||||
};
|
||||
use anyhow::Result;
|
||||
use collections::{BTreeMap, HashMap};
|
||||
|
|
@ -257,6 +257,9 @@ impl EditorElement {
|
|||
register_action(view, cx, Editor::move_to_enclosing_bracket);
|
||||
register_action(view, cx, Editor::undo_selection);
|
||||
register_action(view, cx, Editor::redo_selection);
|
||||
if !view.read(cx).is_singleton(cx) {
|
||||
register_action(view, cx, Editor::expand_excerpts);
|
||||
}
|
||||
register_action(view, cx, Editor::go_to_diagnostic);
|
||||
register_action(view, cx, Editor::go_to_prev_diagnostic);
|
||||
register_action(view, cx, Editor::go_to_hunk);
|
||||
|
|
@ -1543,6 +1546,7 @@ impl EditorElement {
|
|||
range,
|
||||
starts_new_buffer,
|
||||
height,
|
||||
id,
|
||||
..
|
||||
} => {
|
||||
let include_root = self
|
||||
|
|
@ -1700,45 +1704,38 @@ impl EditorElement {
|
|||
)
|
||||
.h_full()
|
||||
.child(
|
||||
ButtonLike::new("jump-icon")
|
||||
ButtonLike::new("expand-icon")
|
||||
.style(ButtonStyle::Transparent)
|
||||
.child(
|
||||
svg()
|
||||
.path(IconName::ArrowUpRight.path())
|
||||
.path(IconName::ExpandVertical.path())
|
||||
.size(IconSize::XSmall.rems())
|
||||
.text_color(cx.theme().colors().border)
|
||||
.group_hover("excerpt-jump-action", |style| {
|
||||
.text_color(
|
||||
cx.theme().colors().editor_line_number,
|
||||
)
|
||||
.group("")
|
||||
.hover(|style| {
|
||||
style.text_color(
|
||||
cx.theme().colors().editor_line_number,
|
||||
cx.theme()
|
||||
.colors()
|
||||
.editor_active_line_number,
|
||||
)
|
||||
}),
|
||||
)
|
||||
.when_some(jump_data.clone(), |this, jump_data| {
|
||||
this.on_click(cx.listener_for(&self.editor, {
|
||||
let path = jump_data.path.clone();
|
||||
move |editor, _, cx| {
|
||||
editor.jump(
|
||||
path.clone(),
|
||||
jump_data.position,
|
||||
jump_data.anchor,
|
||||
jump_data.line_offset_from_top,
|
||||
cx,
|
||||
);
|
||||
}
|
||||
}))
|
||||
.tooltip({
|
||||
move |cx| {
|
||||
Tooltip::for_action(
|
||||
format!(
|
||||
"Jump to {}:L{}",
|
||||
jump_data.path.path.display(),
|
||||
jump_data.position.row + 1
|
||||
),
|
||||
&OpenExcerpts,
|
||||
cx,
|
||||
)
|
||||
}
|
||||
})
|
||||
.on_click(cx.listener_for(&self.editor, {
|
||||
let id = *id;
|
||||
move |editor, _, cx| {
|
||||
editor.expand_excerpt(id, cx);
|
||||
}
|
||||
}))
|
||||
.tooltip({
|
||||
move |cx| {
|
||||
Tooltip::for_action(
|
||||
"Expand Excerpt",
|
||||
&ExpandExcerpts { lines: 0 },
|
||||
cx,
|
||||
)
|
||||
}
|
||||
}),
|
||||
),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -24,14 +24,18 @@ test-support = [
|
|||
anyhow.workspace = true
|
||||
clock.workspace = true
|
||||
collections.workspace = true
|
||||
ctor.workspace = true
|
||||
env_logger.workspace = true
|
||||
futures.workspace = true
|
||||
git.workspace = true
|
||||
gpui.workspace = true
|
||||
itertools.workspace = true
|
||||
language.workspace = true
|
||||
log.workspace = true
|
||||
parking_lot.workspace = true
|
||||
rand.workspace = true
|
||||
settings.workspace = true
|
||||
smallvec.workspace = true
|
||||
sum_tree.workspace = true
|
||||
text.workspace = true
|
||||
theme.workspace = true
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ use collections::{BTreeMap, Bound, HashMap, HashSet};
|
|||
use futures::{channel::mpsc, SinkExt};
|
||||
use git::diff::DiffHunk;
|
||||
use gpui::{AppContext, EventEmitter, Model, ModelContext};
|
||||
use itertools::Itertools;
|
||||
use language::{
|
||||
char_kind,
|
||||
language_settings::{language_settings, LanguageSettings},
|
||||
|
|
@ -15,6 +16,7 @@ use language::{
|
|||
Outline, OutlineItem, Point, PointUtf16, Selection, TextDimension, ToOffset as _,
|
||||
ToOffsetUtf16 as _, ToPoint as _, ToPointUtf16 as _, TransactionId, Unclipped,
|
||||
};
|
||||
use smallvec::SmallVec;
|
||||
use std::{
|
||||
borrow::Cow,
|
||||
cell::{Ref, RefCell},
|
||||
|
|
@ -1008,12 +1010,12 @@ impl MultiBuffer {
|
|||
anchor_ranges.extend(ranges.by_ref().take(range_count).map(|range| {
|
||||
let start = Anchor {
|
||||
buffer_id: Some(buffer_id),
|
||||
excerpt_id: excerpt_id,
|
||||
excerpt_id,
|
||||
text_anchor: buffer_snapshot.anchor_after(range.start),
|
||||
};
|
||||
let end = Anchor {
|
||||
buffer_id: Some(buffer_id),
|
||||
excerpt_id: excerpt_id,
|
||||
excerpt_id,
|
||||
text_anchor: buffer_snapshot.anchor_after(range.end),
|
||||
};
|
||||
start..end
|
||||
|
|
@ -1573,6 +1575,86 @@ impl MultiBuffer {
|
|||
self.as_singleton().unwrap().read(cx).is_parsing()
|
||||
}
|
||||
|
||||
pub fn expand_excerpts(
|
||||
&mut self,
|
||||
ids: impl IntoIterator<Item = ExcerptId>,
|
||||
line_count: u32,
|
||||
cx: &mut ModelContext<Self>,
|
||||
) {
|
||||
if line_count == 0 {
|
||||
return;
|
||||
}
|
||||
self.sync(cx);
|
||||
|
||||
let snapshot = self.snapshot(cx);
|
||||
let locators = snapshot.excerpt_locators_for_ids(ids);
|
||||
let mut new_excerpts = SumTree::new();
|
||||
let mut cursor = snapshot.excerpts.cursor::<(Option<&Locator>, usize)>();
|
||||
let mut edits = Vec::<Edit<usize>>::new();
|
||||
|
||||
for locator in &locators {
|
||||
let prefix = cursor.slice(&Some(locator), Bias::Left, &());
|
||||
new_excerpts.append(prefix, &());
|
||||
|
||||
let mut excerpt = cursor.item().unwrap().clone();
|
||||
let old_text_len = excerpt.text_summary.len;
|
||||
|
||||
let start_row = excerpt
|
||||
.range
|
||||
.context
|
||||
.start
|
||||
.to_point(&excerpt.buffer)
|
||||
.row
|
||||
.saturating_sub(line_count);
|
||||
let start_point = Point::new(start_row, 0);
|
||||
excerpt.range.context.start = excerpt.buffer.anchor_before(start_point);
|
||||
|
||||
let end_point = excerpt.buffer.clip_point(
|
||||
excerpt.range.context.end.to_point(&excerpt.buffer) + Point::new(line_count, 0),
|
||||
Bias::Left,
|
||||
);
|
||||
excerpt.range.context.end = excerpt.buffer.anchor_after(end_point);
|
||||
excerpt.max_buffer_row = end_point.row;
|
||||
|
||||
excerpt.text_summary = excerpt
|
||||
.buffer
|
||||
.text_summary_for_range(start_point..end_point);
|
||||
|
||||
let new_start_offset = new_excerpts.summary().text.len;
|
||||
let old_start_offset = cursor.start().1;
|
||||
let edit = Edit {
|
||||
old: old_start_offset..old_start_offset + old_text_len,
|
||||
new: new_start_offset..new_start_offset + excerpt.text_summary.len,
|
||||
};
|
||||
|
||||
if let Some(last_edit) = edits.last_mut() {
|
||||
if last_edit.old.end == edit.old.start {
|
||||
last_edit.old.end = edit.old.end;
|
||||
last_edit.new.end = edit.new.end;
|
||||
} else {
|
||||
edits.push(edit);
|
||||
}
|
||||
} else {
|
||||
edits.push(edit);
|
||||
}
|
||||
|
||||
new_excerpts.push(excerpt, &());
|
||||
|
||||
cursor.next(&());
|
||||
}
|
||||
|
||||
new_excerpts.append(cursor.suffix(&()), &());
|
||||
|
||||
drop(cursor);
|
||||
self.snapshot.borrow_mut().excerpts = new_excerpts;
|
||||
|
||||
self.subscriptions.publish_mut(edits);
|
||||
cx.emit(Event::Edited {
|
||||
singleton_buffer_edited: false,
|
||||
});
|
||||
cx.notify();
|
||||
}
|
||||
|
||||
fn sync(&self, cx: &AppContext) {
|
||||
let mut snapshot = self.snapshot.borrow_mut();
|
||||
let mut excerpts_to_edit = Vec::new();
|
||||
|
|
@ -1796,6 +1878,19 @@ impl MultiBuffer {
|
|||
log::info!("Clearing multi-buffer");
|
||||
self.clear(cx);
|
||||
continue;
|
||||
} else if rng.gen_bool(0.1) && !self.excerpt_ids().is_empty() {
|
||||
let ids = self.excerpt_ids();
|
||||
let mut excerpts = HashSet::default();
|
||||
for _ in 0..rng.gen_range(0..ids.len()) {
|
||||
excerpts.extend(ids.choose(rng).copied());
|
||||
}
|
||||
|
||||
let line_count = rng.gen_range(0..5);
|
||||
|
||||
log::info!("Expanding excerpts {excerpts:?} by {line_count} lines");
|
||||
|
||||
self.expand_excerpts(excerpts.iter().cloned(), line_count, cx);
|
||||
continue;
|
||||
}
|
||||
|
||||
let excerpt_ids = self.excerpt_ids();
|
||||
|
|
@ -3361,6 +3456,39 @@ impl MultiBufferSnapshot {
|
|||
}
|
||||
}
|
||||
|
||||
// Returns the locators referenced by the given excerpt ids, sorted by locator.
|
||||
fn excerpt_locators_for_ids(
|
||||
&self,
|
||||
ids: impl IntoIterator<Item = ExcerptId>,
|
||||
) -> SmallVec<[Locator; 1]> {
|
||||
let mut sorted_ids = ids.into_iter().collect::<SmallVec<[_; 1]>>();
|
||||
sorted_ids.sort_unstable();
|
||||
let mut locators = SmallVec::new();
|
||||
|
||||
while sorted_ids.last() == Some(&ExcerptId::max()) {
|
||||
sorted_ids.pop();
|
||||
locators.push(Locator::max());
|
||||
}
|
||||
|
||||
let mut sorted_ids = sorted_ids.into_iter().dedup().peekable();
|
||||
if sorted_ids.peek() == Some(&ExcerptId::min()) {
|
||||
sorted_ids.next();
|
||||
locators.push(Locator::min());
|
||||
}
|
||||
|
||||
let mut cursor = self.excerpt_ids.cursor::<ExcerptId>();
|
||||
for id in sorted_ids {
|
||||
if cursor.seek_forward(&id, Bias::Left, &()) {
|
||||
locators.push(cursor.item().unwrap().locator.clone());
|
||||
} else {
|
||||
panic!("invalid excerpt id {:?}", id);
|
||||
}
|
||||
}
|
||||
|
||||
locators.sort_unstable();
|
||||
locators
|
||||
}
|
||||
|
||||
pub fn buffer_id_for_excerpt(&self, excerpt_id: ExcerptId) -> Option<BufferId> {
|
||||
Some(self.excerpt(excerpt_id)?.buffer_id)
|
||||
}
|
||||
|
|
@ -4286,7 +4414,8 @@ where
|
|||
.peekable();
|
||||
while let Some(range) = range_iter.next() {
|
||||
let excerpt_start = Point::new(range.start.row.saturating_sub(context_line_count), 0);
|
||||
let mut excerpt_end = Point::new(range.end.row + context_line_count, 0).min(max_point);
|
||||
// These + 1s ensure that we select the whole next line
|
||||
let mut excerpt_end = Point::new(range.end.row + 1 + context_line_count, 0).min(max_point);
|
||||
|
||||
let mut ranges_in_excerpt = 1;
|
||||
|
||||
|
|
@ -4323,6 +4452,13 @@ mod tests {
|
|||
use std::env;
|
||||
use util::test::sample_text;
|
||||
|
||||
#[ctor::ctor]
|
||||
fn init_logger() {
|
||||
if std::env::var("RUST_LOG").is_ok() {
|
||||
env_logger::init();
|
||||
}
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
fn test_singleton(cx: &mut AppContext) {
|
||||
let buffer = cx.new_model(|cx| Buffer::local(sample_text(6, 6, 'a'), cx));
|
||||
|
|
@ -4721,6 +4857,59 @@ mod tests {
|
|||
assert_eq!(*follower_edit_event_count.read(), 4);
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
fn test_expand_excerpts(cx: &mut AppContext) {
|
||||
let buffer = cx.new_model(|cx| Buffer::local(sample_text(20, 3, 'a'), cx));
|
||||
let multibuffer = cx.new_model(|_| MultiBuffer::new(0, Capability::ReadWrite));
|
||||
|
||||
multibuffer.update(cx, |multibuffer, cx| {
|
||||
multibuffer.push_excerpts_with_context_lines(
|
||||
buffer.clone(),
|
||||
vec![
|
||||
// Note that in this test, this first excerpt
|
||||
// does not contain a new line
|
||||
Point::new(3, 2)..Point::new(3, 3),
|
||||
Point::new(7, 1)..Point::new(7, 3),
|
||||
Point::new(15, 0)..Point::new(15, 0),
|
||||
],
|
||||
1,
|
||||
cx,
|
||||
)
|
||||
});
|
||||
|
||||
multibuffer.update(cx, |multibuffer, cx| {
|
||||
multibuffer.expand_excerpts(multibuffer.excerpt_ids(), 1, cx)
|
||||
});
|
||||
|
||||
let snapshot = multibuffer.read(cx).snapshot(cx);
|
||||
|
||||
// Expanding context lines causes the line containing 'fff' to appear in two different excerpts.
|
||||
// We don't attempt to merge them, because removing the excerpt could create inconsistency with other layers
|
||||
// that are tracking excerpt ids.
|
||||
assert_eq!(
|
||||
snapshot.text(),
|
||||
concat!(
|
||||
"bbb\n", // Preserve newlines
|
||||
"ccc\n", //
|
||||
"ddd\n", //
|
||||
"eee\n", //
|
||||
"fff\n", // <- Same as below
|
||||
"\n", // Excerpt boundary
|
||||
"fff\n", // <- Same as above
|
||||
"ggg\n", //
|
||||
"hhh\n", //
|
||||
"iii\n", //
|
||||
"jjj\n", //
|
||||
"\n", //
|
||||
"nnn\n", //
|
||||
"ooo\n", //
|
||||
"ppp\n", //
|
||||
"qqq\n", //
|
||||
"rrr\n", //
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
fn test_push_excerpts_with_context_lines(cx: &mut AppContext) {
|
||||
let buffer = cx.new_model(|cx| Buffer::local(sample_text(20, 3, 'a'), cx));
|
||||
|
|
@ -4729,6 +4918,8 @@ mod tests {
|
|||
multibuffer.push_excerpts_with_context_lines(
|
||||
buffer.clone(),
|
||||
vec![
|
||||
// Note that in this test, this first excerpt
|
||||
// does contain a new line
|
||||
Point::new(3, 2)..Point::new(4, 2),
|
||||
Point::new(7, 1)..Point::new(7, 3),
|
||||
Point::new(15, 0)..Point::new(15, 0),
|
||||
|
|
@ -4741,7 +4932,23 @@ mod tests {
|
|||
let snapshot = multibuffer.read(cx).snapshot(cx);
|
||||
assert_eq!(
|
||||
snapshot.text(),
|
||||
"bbb\nccc\nddd\neee\nfff\nggg\nhhh\niii\njjj\n\nnnn\nooo\nppp\nqqq\n"
|
||||
concat!(
|
||||
"bbb\n", // Preserve newlines
|
||||
"ccc\n", //
|
||||
"ddd\n", //
|
||||
"eee\n", //
|
||||
"fff\n", //
|
||||
"ggg\n", //
|
||||
"hhh\n", //
|
||||
"iii\n", //
|
||||
"jjj\n", //
|
||||
"\n", //
|
||||
"nnn\n", //
|
||||
"ooo\n", //
|
||||
"ppp\n", //
|
||||
"qqq\n", //
|
||||
"rrr\n", //
|
||||
)
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
|
|
@ -4777,7 +4984,23 @@ mod tests {
|
|||
let snapshot = multibuffer.update(cx, |multibuffer, cx| multibuffer.snapshot(cx));
|
||||
assert_eq!(
|
||||
snapshot.text(),
|
||||
"bbb\nccc\nddd\neee\nfff\nggg\nhhh\niii\njjj\n\nnnn\nooo\nppp\nqqq\n"
|
||||
concat!(
|
||||
"bbb\n", //
|
||||
"ccc\n", //
|
||||
"ddd\n", //
|
||||
"eee\n", //
|
||||
"fff\n", //
|
||||
"ggg\n", //
|
||||
"hhh\n", //
|
||||
"iii\n", //
|
||||
"jjj\n", //
|
||||
"\n", //
|
||||
"nnn\n", //
|
||||
"ooo\n", //
|
||||
"ppp\n", //
|
||||
"qqq\n", //
|
||||
"rrr\n", //
|
||||
)
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
|
|
@ -5027,10 +5250,45 @@ mod tests {
|
|||
|
||||
for _ in 0..operations {
|
||||
match rng.gen_range(0..100) {
|
||||
0..=19 if !buffers.is_empty() => {
|
||||
0..=14 if !buffers.is_empty() => {
|
||||
let buffer = buffers.choose(&mut rng).unwrap();
|
||||
buffer.update(cx, |buf, cx| buf.randomly_edit(&mut rng, 5, cx));
|
||||
}
|
||||
15..=19 if !expected_excerpts.is_empty() => {
|
||||
multibuffer.update(cx, |multibuffer, cx| {
|
||||
let ids = multibuffer.excerpt_ids();
|
||||
let mut excerpts = HashSet::default();
|
||||
for _ in 0..rng.gen_range(0..ids.len()) {
|
||||
excerpts.extend(ids.choose(&mut rng).copied());
|
||||
}
|
||||
|
||||
let line_count = rng.gen_range(0..5);
|
||||
|
||||
let excerpt_ixs = excerpts
|
||||
.iter()
|
||||
.map(|id| excerpt_ids.iter().position(|i| i == id).unwrap())
|
||||
.collect::<Vec<_>>();
|
||||
log::info!("Expanding excerpts {excerpt_ixs:?} by {line_count} lines");
|
||||
multibuffer.expand_excerpts(excerpts.iter().cloned(), line_count, cx);
|
||||
|
||||
if line_count > 0 {
|
||||
for id in excerpts {
|
||||
let excerpt_ix = excerpt_ids.iter().position(|&i| i == id).unwrap();
|
||||
let (buffer, range) = &mut expected_excerpts[excerpt_ix];
|
||||
let snapshot = buffer.read(cx).snapshot();
|
||||
let mut point_range = range.to_point(&snapshot);
|
||||
point_range.start =
|
||||
Point::new(point_range.start.row.saturating_sub(line_count), 0);
|
||||
point_range.end = snapshot.clip_point(
|
||||
Point::new(point_range.end.row + line_count, 0),
|
||||
Bias::Left,
|
||||
);
|
||||
*range = snapshot.anchor_before(point_range.start)
|
||||
..snapshot.anchor_after(point_range.end);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
20..=29 if !expected_excerpts.is_empty() => {
|
||||
let mut ids_to_remove = vec![];
|
||||
for _ in 0..rng.gen_range(1..=3) {
|
||||
|
|
@ -5093,8 +5351,9 @@ mod tests {
|
|||
_ => {
|
||||
let buffer_handle = if buffers.is_empty() || rng.gen_bool(0.4) {
|
||||
let base_text = util::RandomCharIter::new(&mut rng)
|
||||
.take(10)
|
||||
.take(25)
|
||||
.collect::<String>();
|
||||
|
||||
buffers.push(cx.new_model(|cx| Buffer::local(base_text, cx)));
|
||||
buffers.last().unwrap()
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -405,6 +405,7 @@ where
|
|||
summary.0
|
||||
}
|
||||
|
||||
/// Returns whether we found the item you where seeking for
|
||||
fn seek_internal(
|
||||
&mut self,
|
||||
target: &dyn SeekTarget<'a, T::Summary, D>,
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@ pub enum IconName {
|
|||
ChevronLeft,
|
||||
ChevronRight,
|
||||
ChevronUp,
|
||||
ExpandVertical,
|
||||
Close,
|
||||
Collab,
|
||||
Command,
|
||||
|
|
@ -149,6 +150,7 @@ impl IconName {
|
|||
IconName::ChevronLeft => "icons/chevron_left.svg",
|
||||
IconName::ChevronRight => "icons/chevron_right.svg",
|
||||
IconName::ChevronUp => "icons/chevron_up.svg",
|
||||
IconName::ExpandVertical => "icons/expand_vertical.svg",
|
||||
IconName::Close => "icons/x.svg",
|
||||
IconName::Collab => "icons/user_group_16.svg",
|
||||
IconName::Command => "icons/command.svg",
|
||||
|
|
|
|||
|
|
@ -289,7 +289,6 @@ define_connection! {
|
|||
sql!(
|
||||
ALTER TABLE workspaces ADD COLUMN centered_layout INTEGER; //bool
|
||||
),
|
||||
|
||||
];
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue