From 8a02159b8232f54f8f39d8939f659a71892e872c Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Fri, 19 Apr 2024 14:27:56 -0700 Subject: [PATCH] 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 Co-authored-by: Max --- Cargo.lock | 4 + assets/icons/LICENSES | 9 + assets/icons/expand_vertical.svg | 1 + assets/keymaps/default-linux.json | 1 + assets/keymaps/default-macos.json | 1 + crates/editor/src/actions.rs | 9 +- crates/editor/src/editor.rs | 22 ++ crates/editor/src/element.rs | 65 +++--- crates/multi_buffer/Cargo.toml | 4 + crates/multi_buffer/src/multi_buffer.rs | 273 +++++++++++++++++++++++- crates/sum_tree/src/cursor.rs | 1 + crates/ui/src/components/icon.rs | 2 + crates/workspace/src/persistence.rs | 1 - script/generate-licenses | 5 +- 14 files changed, 353 insertions(+), 45 deletions(-) create mode 100644 assets/icons/LICENSES create mode 100644 assets/icons/expand_vertical.svg diff --git a/Cargo.lock b/Cargo.lock index 63aa72410f..57466fb0f7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6051,14 +6051,18 @@ dependencies = [ "anyhow", "clock", "collections", + "ctor", + "env_logger", "futures 0.3.28", "git", "gpui", + "itertools 0.11.0", "language", "log", "parking_lot", "rand 0.8.5", "settings", + "smallvec", "sum_tree", "text", "theme", diff --git a/assets/icons/LICENSES b/assets/icons/LICENSES new file mode 100644 index 0000000000..7a2fc3b863 --- /dev/null +++ b/assets/icons/LICENSES @@ -0,0 +1,9 @@ +Lucide License + +ISC License + +Copyright (c) for portions of Lucide are held by Cole Bemis 2013-2022 as part of Feather (MIT). All other copyright (c) for Lucide are held by Lucide Contributors 2022. + +Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/assets/icons/expand_vertical.svg b/assets/icons/expand_vertical.svg new file mode 100644 index 0000000000..e278911478 --- /dev/null +++ b/assets/icons/expand_vertical.svg @@ -0,0 +1 @@ + diff --git a/assets/keymaps/default-linux.json b/assets/keymaps/default-linux.json index e285ef3384..209699b3cd 100644 --- a/assets/keymaps/default-linux.json +++ b/assets/keymaps/default-linux.json @@ -527,6 +527,7 @@ "context": "Editor && mode == full", "bindings": { "alt-enter": "editor::OpenExcerpts", + "shift-enter": "editor::ExpandExcerpts", "ctrl-k enter": "editor::OpenExcerptsSplit", "ctrl-f8": "editor::GoToHunk", "ctrl-shift-f8": "editor::GoToPrevHunk", diff --git a/assets/keymaps/default-macos.json b/assets/keymaps/default-macos.json index 9aaa577694..f909bd48c5 100644 --- a/assets/keymaps/default-macos.json +++ b/assets/keymaps/default-macos.json @@ -541,6 +541,7 @@ "context": "Editor && mode == full", "bindings": { "alt-enter": "editor::OpenExcerpts", + "shift-enter": "editor::ExpandExcerpts", "cmd-k enter": "editor::OpenExcerptsSplit", "cmd-f8": "editor::GoToHunk", "cmd-shift-f8": "editor::GoToPrevHunk", diff --git a/crates/editor/src/actions.rs b/crates/editor/src/actions.rs index a5a3e4fee1..1494c23c00 100644 --- a/crates/editor/src/actions.rs +++ b/crates/editor/src/actions.rs @@ -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, ] ); diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index 9605d6842d..3356d507cd 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -7462,6 +7462,28 @@ impl Editor { self.selection_history.mode = SelectionHistoryMode::Normal; } + pub fn expand_excerpts(&mut self, action: &ExpandExcerpts, cx: &mut ViewContext) { + 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.buffer + .update(cx, |buffer, cx| buffer.expand_excerpts([excerpt], 3, cx)) + } + fn go_to_diagnostic(&mut self, _: &GoToDiagnostic, cx: &mut ViewContext) { self.go_to_diagnostic_impl(Direction::Next, cx) } diff --git a/crates/editor/src/element.rs b/crates/editor/src/element.rs index b8ee1643c6..98837be7b9 100644 --- a/crates/editor/src/element.rs +++ b/crates/editor/src/element.rs @@ -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, + ) + } }), ), ) diff --git a/crates/multi_buffer/Cargo.toml b/crates/multi_buffer/Cargo.toml index f866217da8..611cec57e0 100644 --- a/crates/multi_buffer/Cargo.toml +++ b/crates/multi_buffer/Cargo.toml @@ -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 diff --git a/crates/multi_buffer/src/multi_buffer.rs b/crates/multi_buffer/src/multi_buffer.rs index 365f8d1e1b..ee2d00aa04 100644 --- a/crates/multi_buffer/src/multi_buffer.rs +++ b/crates/multi_buffer/src/multi_buffer.rs @@ -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, + line_count: u32, + cx: &mut ModelContext, + ) { + 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::>::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, + ) -> SmallVec<[Locator; 1]> { + let mut sorted_ids = ids.into_iter().collect::>(); + 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::(); + 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 { 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::>(); + 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::(); + buffers.push(cx.new_model(|cx| Buffer::local(base_text, cx))); buffers.last().unwrap() } else { diff --git a/crates/sum_tree/src/cursor.rs b/crates/sum_tree/src/cursor.rs index 12ab12dc27..4604d9e9ff 100644 --- a/crates/sum_tree/src/cursor.rs +++ b/crates/sum_tree/src/cursor.rs @@ -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>, diff --git a/crates/ui/src/components/icon.rs b/crates/ui/src/components/icon.rs index 1bf4505032..f31db36204 100644 --- a/crates/ui/src/components/icon.rs +++ b/crates/ui/src/components/icon.rs @@ -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", diff --git a/crates/workspace/src/persistence.rs b/crates/workspace/src/persistence.rs index 322945c9c0..3c4efa7669 100644 --- a/crates/workspace/src/persistence.rs +++ b/crates/workspace/src/persistence.rs @@ -289,7 +289,6 @@ define_connection! { sql!( ALTER TABLE workspaces ADD COLUMN centered_layout INTEGER; //bool ), - ]; } diff --git a/script/generate-licenses b/script/generate-licenses index 79dd884514..d2c3aa3bcf 100755 --- a/script/generate-licenses +++ b/script/generate-licenses @@ -7,10 +7,11 @@ OUTPUT_FILE="${1:-$(pwd)/assets/licenses.md}" > $OUTPUT_FILE echo -e "# ###### THEME LICENSES ######\n" >> $OUTPUT_FILE - -echo "Generating theme licenses" cat assets/themes/LICENSES >> $OUTPUT_FILE +echo -e "# ###### ICON LICENSES ######\n" >> $OUTPUT_FILE +cat assets/icons/LICENSES >> $OUTPUT_FILE + echo -e "# ###### CODE LICENSES ######\n" >> $OUTPUT_FILE [[ "$(cargo about --version)" == "cargo-about 0.6.1" ]] || cargo install cargo-about@0.6.1