diff --git a/lapce-app/src/app.rs b/lapce-app/src/app.rs index f49d0fa8..d3066b41 100644 --- a/lapce-app/src/app.rs +++ b/lapce-app/src/app.rs @@ -11,9 +11,9 @@ parley::style::FontWeight, peniko::kurbo::{Point, Rect, Size}, reactive::{ - create_effect, create_memo, provide_context, ReadSignal, RwSignal, - SignalGet, SignalGetUntracked, SignalSet, SignalUpdate, SignalWith, - SignalWithUntracked, + create_effect, create_memo, create_rw_signal, provide_context, ReadSignal, + RwSignal, SignalGet, SignalGetUntracked, SignalSet, SignalUpdate, + SignalWith, SignalWithUntracked, }, stack::stack, style::{ @@ -46,7 +46,7 @@ main_split::{MainSplitData, SplitContent, SplitData, SplitDirection}, palette::{ item::{PaletteItem, PaletteItemContent}, - PaletteStatus, + PaletteData, PaletteStatus, }, title::title, window::WindowData, @@ -259,17 +259,8 @@ fn insert_cursor( } fn editor_gutter(cx: AppContext, editor: RwSignal) -> impl View { - let (doc, cursor, scroll_delta, viewport, gutter_viewport, config) = editor - .with(|editor| { - ( - editor.doc.read_only(), - editor.cursor.read_only(), - editor.scroll_delta.read_only(), - editor.viewport, - editor.gutter_viewport, - editor.config, - ) - }); + let (viewport, gutter_viewport, config) = editor + .with(|editor| (editor.viewport, editor.gutter_viewport, editor.config)); stack(cx, |cx| { ( @@ -280,7 +271,10 @@ fn editor_gutter(cx: AppContext, editor: RwSignal) -> impl View { ..Default::default() }), label(cx, move || { - doc.with(|doc| (doc.buffer().last_line() + 1).to_string()) + editor + .get() + .doc + .with(|doc| (doc.buffer().last_line() + 1).to_string()) }) .style(cx, || Style { ..Default::default() @@ -299,7 +293,7 @@ fn editor_gutter(cx: AppContext, editor: RwSignal) -> impl View { virtual_list( cx, VirtualListDirection::Vertical, - move || doc.get(), + move || editor.get().doc.get(), |line: &DocLine| line.line, move |cx, line: DocLine| { stack(cx, move |cx| { @@ -379,7 +373,7 @@ fn editor_gutter(cx: AppContext, editor: RwSignal) -> impl View { fn editor_cursor( cx: AppContext, - doc: ReadSignal, + editor: RwSignal, cursor: ReadSignal, viewport: ReadSignal, is_active: impl Fn() -> bool + 'static, @@ -394,7 +388,7 @@ fn editor_cursor( let max_line = (viewport.y1 / line_height).ceil() as usize; let is_active = is_active(); - + let doc = editor.get().doc; doc.with(|doc| { cursor.with(|cursor| match &cursor.mode { CursorMode::Normal(offset) => { @@ -488,11 +482,10 @@ fn editor_cursor( fn editor( cx: AppContext, - active_editor_tab: ReadSignal>, + is_active: impl Fn() -> bool + 'static, editor: RwSignal, ) -> impl View { let ( - doc, cursor, scroll_delta, scroll_to, @@ -502,7 +495,6 @@ fn editor( config, ) = editor.with(|editor| { ( - editor.doc.read_only(), editor.cursor.read_only(), editor.scroll_delta.read_only(), editor.scroll_to, @@ -513,12 +505,6 @@ fn editor( ) }); - let is_active = move || { - let active_editor_tab = active_editor_tab.get(); - let editor_tab = editor.with(|editor| editor.editor_tab_id); - editor_tab.is_some() && editor_tab == active_editor_tab - }; - let key_fn = |line: &DocLine| (line.rev, line.style_rev, line.line); let view_fn = move |cx, line: DocLine| { container(cx, |cx| { @@ -576,7 +562,7 @@ fn editor( ( editor_cursor( cx, - doc, + editor, cursor, viewport.read_only(), is_active, @@ -588,7 +574,7 @@ fn editor( virtual_list( cx, VirtualListDirection::Vertical, - move || doc.get(), + move || editor.get().doc.get(), key_fn, view_fn, VirtualListItemSize::Fixed(line_height as f64), @@ -624,6 +610,8 @@ fn editor( .on_ensure_visible(cx, move || { let cursor = cursor.get(); let offset = cursor.offset(); + let editor = editor.get(); + let doc = editor.doc; let caret = doc.with_untracked(|doc| { cursor_caret(doc, offset, !cursor.is_insert()) }); @@ -986,8 +974,14 @@ fn editor_tab_content( let editor_data = editors.with(|editors| editors.get(&editor_id).cloned()); if let Some(editor_data) = editor_data { + let is_active = move || { + let active_editor_tab = active_editor_tab.get(); + let editor_tab = + editor_data.with(|editor| editor.editor_tab_id); + editor_tab.is_some() && editor_tab == active_editor_tab + }; container_box(cx, |cx| { - Box::new(editor(cx, active_editor_tab, editor_data)) + Box::new(editor(cx, is_active, editor_data)) }) } else { container_box(cx, |cx| { @@ -1462,8 +1456,8 @@ fn palette_item( } fn palette_input(cx: AppContext, window_tab_data: Arc) -> impl View { - let doc = window_tab_data.palette.editor.doc.read_only(); - let cursor = window_tab_data.palette.editor.cursor.read_only(); + let doc = window_tab_data.palette.input_editor.doc.read_only(); + let cursor = window_tab_data.palette.input_editor.cursor.read_only(); let config = window_tab_data.palette.config; let cursor_x = create_memo(cx.scope, move |_| { let offset = cursor.get().offset(); @@ -1558,6 +1552,7 @@ fn slice(&mut self, range: Range) -> Self::ItemIterator { fn palette_content( cx: AppContext, window_tab_data: Arc, + layout_rect: ReadSignal, ) -> impl View { let items = window_tab_data.palette.filtered_items; let index = window_tab_data.palette.index.read_only(); @@ -1613,36 +1608,68 @@ fn palette_content( ) }) .style(cx, move || Style { - // display: if items.with(|items| items.is_empty()) { - // Display::None - // } else { - // Display::Flex - // }, flex_direction: FlexDirection::Column, width: Dimension::Percent(1.0), min_height: Dimension::Points(0.0), + max_height: Dimension::Points( + (layout_rect.get().height() * 0.45 - 36.0).round() as f32, + ), padding_bottom: 5.0, ..Default::default() }) } +fn palette_preview(cx: AppContext, palette_data: PaletteData) -> impl View { + let preview_editor = palette_data.preview_editor; + let has_preview = palette_data.has_preview; + container(cx, |cx| { + editor(cx, || true, preview_editor).style(cx, move || Style { + position: Position::Absolute, + width: Dimension::Percent(1.0), + height: Dimension::Percent(1.0), + ..Default::default() + }) + }) + .style(cx, move || Style { + display: if has_preview.get() { + Display::Flex + } else { + Display::None + }, + flex_grow: 1.0, + ..Default::default() + }) +} + fn palette(cx: AppContext, window_tab_data: Arc) -> impl View { - let keypress = window_tab_data.keypress.write_only(); + let layout_rect = window_tab_data.layout_rect.read_only(); let palette_data = window_tab_data.palette.clone(); let status = palette_data.status.read_only(); let config = palette_data.config; + let has_preview = palette_data.has_preview.read_only(); container(cx, |cx| { stack(cx, |cx| { ( palette_input(cx, window_tab_data.clone()), - palette_content(cx, window_tab_data.clone()), + palette_content(cx, window_tab_data.clone(), layout_rect), + palette_preview(cx, palette_data), ) }) .style(cx, move || Style { width: Dimension::Points(500.0), max_width: Dimension::Percent(0.9), - min_height: Dimension::Points(0.0), - max_height: Dimension::Percent(0.5), + // min_height: Dimension::Points(0.0), + // max_height: Dimension::Points(layout_rect.get().height() as f32 - 100.0), + max_height: if has_preview.get() { + Dimension::Auto + } else { + Dimension::Percent(1.0) + }, + height: if has_preview.get() { + Dimension::Points(layout_rect.get().height() as f32 - 10.0) + } else { + Dimension::Auto + }, margin_top: Some(5.0), border: 1.0, border_radius: 6.0, diff --git a/lapce-app/src/editor.rs b/lapce-app/src/editor.rs index 0f49e743..86f09e0a 100644 --- a/lapce-app/src/editor.rs +++ b/lapce-app/src/editor.rs @@ -1016,6 +1016,52 @@ fn update_snippet_offset(&self, delta: &RopeDelta) { } } + pub fn go_to_location( + &self, + cx: AppContext, + location: EditorLocation, + new_doc: bool, + ) { + if !new_doc { + if let Some(position) = location.position { + let editor = self.clone(); + let send = create_ext_action(cx, move |position| { + editor.go_to_position(position, location.scroll_offset); + }); + std::thread::spawn(move || { + send(position); + }); + } + } else { + let buffer_id = self.doc.with_untracked(|doc| doc.buffer_id); + let set_doc = self.doc.write_only(); + let editor = self.clone(); + let send = create_ext_action(cx, move |content| { + set_doc.update(move |doc| { + doc.init_content(content); + }); + + if let Some(position) = location.position { + let editor = editor.clone(); + let send = create_ext_action(cx, move |position| { + editor.go_to_position(position, location.scroll_offset); + }); + std::thread::spawn(move || { + send(position); + }); + } + }); + + self.proxy + .new_buffer(buffer_id, location.path, move |result| { + if let Ok(ProxyResponse::NewBufferResponse { content }) = result + { + send(Rope::from(content)) + } + }); + } + } + pub fn go_to_position( &self, position: EditorPosition, diff --git a/lapce-app/src/main_split.rs b/lapce-app/src/main_split.rs index 981964c3..6fbb5941 100644 --- a/lapce-app/src/main_split.rs +++ b/lapce-app/src/main_split.rs @@ -205,10 +205,13 @@ pub fn jump_to_location(&self, cx: AppContext, location: EditorLocation) { self.go_to_location(cx, location); } - pub fn go_to_location(&self, cx: AppContext, location: EditorLocation) { - let path = location.path; + pub fn get_doc( + &self, + cx: AppContext, + path: PathBuf, + ) -> (RwSignal, bool) { let doc = self.docs.with_untracked(|docs| docs.get(&path).cloned()); - let (doc, new) = if let Some(doc) = doc { + if let Some(doc) = doc { (doc, false) } else { let doc = @@ -217,22 +220,7 @@ pub fn go_to_location(&self, cx: AppContext, location: EditorLocation) { self.docs.update(|docs| { docs.insert(path.clone(), doc); }); - (doc, true) - }; - let editor = self.get_editor_or_new(cx, doc, &path); - if !new { - if let Some(position) = location.position { - let send = create_ext_action(cx, move |position| { - editor.with_untracked(|editor| { - editor.go_to_position(position, location.scroll_offset); - }) - }); - std::thread::spawn(move || { - send(position); - }); - } - } else { { let proxy = self.proxy_rpc.clone(); create_effect(cx.scope, move |last| { @@ -245,33 +233,19 @@ pub fn go_to_location(&self, cx: AppContext, location: EditorLocation) { }); } - let buffer_id = doc.with_untracked(|doc| doc.buffer_id); - let set_doc = doc.write_only(); - let send = create_ext_action(cx, move |content| { - set_doc.update(move |doc| { - doc.init_content(content); - }); - - if let Some(position) = location.position { - let send = create_ext_action(cx, move |position| { - editor.with_untracked(|editor| { - editor.go_to_position(position, location.scroll_offset); - }) - }); - std::thread::spawn(move || { - send(position); - }); - } - }); - - self.proxy_rpc.new_buffer(buffer_id, path, move |result| { - if let Ok(ProxyResponse::NewBufferResponse { content }) = result { - send(Rope::from(content)) - } - }); + (doc, true) } } + pub fn go_to_location(&self, cx: AppContext, location: EditorLocation) { + let path = location.path.clone(); + let (doc, new_doc) = self.get_doc(cx, path.clone()); + + let editor = self.get_editor_or_new(cx, doc, &path); + let editor = editor.get_untracked(); + editor.go_to_location(cx, location, new_doc); + } + fn get_editor_or_new( &self, cx: AppContext, diff --git a/lapce-app/src/palette.rs b/lapce-app/src/palette.rs index be5364fd..d1663296 100644 --- a/lapce-app/src/palette.rs +++ b/lapce-app/src/palette.rs @@ -40,6 +40,7 @@ editor::{location::EditorLocation, EditorData}, id::EditorId, keypress::{condition::Condition, KeyPressData, KeyPressFocus}, + main_split::MainSplitData, window_tab::Focus, workspace::{LapceWorkspace, LapceWorkspaceType}, }; @@ -88,12 +89,15 @@ pub struct PaletteData { pub proxy_rpc: ProxyRpcHandler, pub input: RwSignal, kind: RwSignal, - pub editor: EditorData, + pub input_editor: EditorData, + pub preview_editor: RwSignal, + pub has_preview: RwSignal, pub focus: RwSignal, pub keypress: ReadSignal, pub config: ReadSignal>, pub executed_commands: Rc>>, + main_split: MainSplitData, pub references: RwSignal>, } @@ -101,6 +105,7 @@ impl PaletteData { pub fn new( cx: AppContext, workspace: Arc, + main_split: MainSplitData, proxy_rpc: ProxyRpcHandler, register: RwSignal, completion: RwSignal, @@ -123,7 +128,7 @@ pub fn new( }, ); let kind = create_rw_signal(cx.scope, PaletteKind::File); - let editor = EditorData::new_local( + let input_editor = EditorData::new_local( cx, EditorId::next(), register, @@ -132,6 +137,17 @@ pub fn new( proxy_rpc.clone(), config, ); + let preview_editor = EditorData::new_local( + cx, + EditorId::next(), + register, + completion, + internal_command, + proxy_rpc.clone(), + config, + ); + let preview_editor = create_rw_signal(cx.scope, preview_editor); + let has_preview = create_rw_signal(cx.scope, false); let run_id = create_rw_signal(cx.scope, 0); let run_id_counter = Arc::new(AtomicU64::new(0)); @@ -198,6 +214,7 @@ pub fn new( let palette = Self { run_id_counter, run_tx, + main_split, window_command, internal_command, lapce_command, @@ -208,7 +225,9 @@ pub fn new( index, items, filtered_items, - editor, + input_editor, + preview_editor, + has_preview, input, kind, proxy_rpc, @@ -220,7 +239,7 @@ pub fn new( { let palette = palette.clone(); - let doc = palette.editor.doc.read_only(); + let doc = palette.input_editor.doc.read_only(); let input = palette.input.write_only(); let status = palette.status.read_only(); let preset_kind = palette.kind.read_only(); @@ -267,6 +286,14 @@ pub fn new( }); } + { + let palette = palette.clone(); + create_effect(cx.scope, move |_| { + let _ = palette.index.get(); + palette.preview(cx); + }); + } + palette } @@ -275,15 +302,16 @@ pub fn run(&self, cx: AppContext, kind: PaletteKind) { self.status.set(PaletteStatus::Started); let symbol = kind.symbol(); self.kind.set(kind); - self.editor + self.input_editor .doc .update(|doc| doc.reload(Rope::from(symbol), true)); - self.editor + self.input_editor .cursor .update(|cursor| cursor.set_insert(Selection::caret(symbol.len()))); } fn run_inner(&self, cx: AppContext, kind: PaletteKind) { + self.has_preview.set(false); let run_id = self.run_id_counter.fetch_add(1, Ordering::Relaxed) + 1; self.run_id.set(run_id); match kind { @@ -477,14 +505,36 @@ fn select(&self, cx: AppContext) { self.cancel(cx); } + fn preview(&self, cx: AppContext) { + let index = self.index.get_untracked(); + let items = self.filtered_items.get_untracked(); + if let Some(item) = items.get(index) { + match &item.content { + PaletteItemContent::File { path, full_path } => {} + PaletteItemContent::Command { cmd } => {} + PaletteItemContent::Workspace { workspace } => {} + PaletteItemContent::Reference { path, location } => { + self.has_preview.set(true); + let (doc, new_doc) = + self.main_split.get_doc(cx, location.path.clone()); + self.preview_editor.update(|preview_editor| { + preview_editor.doc = doc; + preview_editor.go_to_location(cx, location.clone(), new_doc); + }); + } + } + } + } + fn cancel(&self, cx: AppContext) { self.status.set(PaletteStatus::Inactive); self.focus.set(Focus::Workbench); + self.has_preview.set(false); self.items.update(|items| items.clear()); - self.editor + self.input_editor .doc .update(|doc| doc.reload(Rope::from(""), true)); - self.editor + self.input_editor .cursor .update(|cursor| cursor.set_insert(Selection::caret(0))); } @@ -645,10 +695,10 @@ fn run_command( match &command.kind { CommandKind::Workbench(_) => todo!(), CommandKind::Edit(_) => { - self.editor.run_command(cx, command, count, mods) + self.input_editor.run_command(cx, command, count, mods) } CommandKind::Move(_) => { - self.editor.run_command(cx, command, count, mods) + self.input_editor.run_command(cx, command, count, mods) } CommandKind::Focus(cmd) => self.run_focus_command(cx, cmd), CommandKind::MotionMode(_) => todo!(), @@ -657,6 +707,6 @@ fn run_command( } fn receive_char(&self, cx: AppContext, c: &str) { - self.editor.receive_char(cx, c); + self.input_editor.receive_char(cx, c); } } diff --git a/lapce-app/src/window_tab.rs b/lapce-app/src/window_tab.rs index e832dde3..3da50d3b 100644 --- a/lapce-app/src/window_tab.rs +++ b/lapce-app/src/window_tab.rs @@ -87,9 +87,19 @@ pub fn new( let register = create_rw_signal(cx.scope, Register::default()); + let main_split = MainSplitData::new( + cx, + proxy.rpc.clone(), + register, + completion, + set_internal_command, + config, + ); + let palette = PaletteData::new( cx, workspace.clone(), + main_split.clone(), proxy.rpc.clone(), register, completion, @@ -101,15 +111,6 @@ pub fn new( config, ); - let main_split = MainSplitData::new( - cx, - proxy.rpc.clone(), - register, - completion, - set_internal_command, - config, - ); - let window_tab_data = Self { window_tab_id: WindowTabId::next(), set_window_command,