From 103206f50a95e6d94601edc7041219298044d8ec Mon Sep 17 00:00:00 2001 From: Dongdong Zhou Date: Wed, 7 Aug 2024 21:17:14 +0100 Subject: [PATCH] editor gutter refactor Use code actions popup for CodeLens --- Cargo.lock | 13 +- Cargo.toml | 4 +- lapce-app/src/app.rs | 2 +- lapce-app/src/code_action.rs | 12 +- lapce-app/src/code_lens.rs | 94 +++ lapce-app/src/command.rs | 5 +- lapce-app/src/doc.rs | 66 +- lapce-app/src/editor.rs | 30 +- lapce-app/src/editor/gutter.rs | 21 +- lapce-app/src/editor/view.rs | 780 +++++++++++----------- lapce-app/src/file_explorer/view.rs | 4 +- lapce-app/src/lib.rs | 1 + lapce-app/src/main_split.rs | 99 +-- lapce-app/src/panel/global_search_view.rs | 2 +- lapce-app/src/panel/problem_view.rs | 2 +- lapce-app/src/settings.rs | 8 +- lapce-app/src/window_tab.rs | 33 +- 17 files changed, 622 insertions(+), 554 deletions(-) create mode 100644 lapce-app/src/code_lens.rs diff --git a/Cargo.lock b/Cargo.lock index 1d3d304e62..f08869645e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1684,7 +1684,7 @@ checksum = "98de4bbd547a563b716d8dfa9aad1cb19bfab00f4fa09a6a4ed21dbcf44ce9c4" [[package]] name = "floem" version = "0.1.1" -source = "git+https://github.com/lapce/floem?rev=48d2b6eb22a02a100d67868052ecc35fa3c42e10#48d2b6eb22a02a100d67868052ecc35fa3c42e10" +source = "git+https://github.com/lapce/floem?rev=54f0d1bcf0e1a91d82492ee7300a526adb60eb5c#54f0d1bcf0e1a91d82492ee7300a526adb60eb5c" dependencies = [ "bitflags 2.6.0", "copypasta", @@ -1722,7 +1722,7 @@ dependencies = [ [[package]] name = "floem-editor-core" version = "0.1.1" -source = "git+https://github.com/lapce/floem?rev=48d2b6eb22a02a100d67868052ecc35fa3c42e10#48d2b6eb22a02a100d67868052ecc35fa3c42e10" +source = "git+https://github.com/lapce/floem?rev=54f0d1bcf0e1a91d82492ee7300a526adb60eb5c#54f0d1bcf0e1a91d82492ee7300a526adb60eb5c" dependencies = [ "bitflags 2.6.0", "itertools 0.12.1", @@ -1800,7 +1800,7 @@ dependencies = [ [[package]] name = "floem_reactive" version = "0.1.1" -source = "git+https://github.com/lapce/floem?rev=48d2b6eb22a02a100d67868052ecc35fa3c42e10#48d2b6eb22a02a100d67868052ecc35fa3c42e10" +source = "git+https://github.com/lapce/floem?rev=54f0d1bcf0e1a91d82492ee7300a526adb60eb5c#54f0d1bcf0e1a91d82492ee7300a526adb60eb5c" dependencies = [ "smallvec", ] @@ -1808,19 +1808,20 @@ dependencies = [ [[package]] name = "floem_renderer" version = "0.1.1" -source = "git+https://github.com/lapce/floem?rev=48d2b6eb22a02a100d67868052ecc35fa3c42e10#48d2b6eb22a02a100d67868052ecc35fa3c42e10" +source = "git+https://github.com/lapce/floem?rev=54f0d1bcf0e1a91d82492ee7300a526adb60eb5c#54f0d1bcf0e1a91d82492ee7300a526adb60eb5c" dependencies = [ "cosmic-text", "image", "parking_lot", "peniko", "resvg", + "swash", ] [[package]] name = "floem_tiny_skia_renderer" version = "0.1.1" -source = "git+https://github.com/lapce/floem?rev=48d2b6eb22a02a100d67868052ecc35fa3c42e10#48d2b6eb22a02a100d67868052ecc35fa3c42e10" +source = "git+https://github.com/lapce/floem?rev=54f0d1bcf0e1a91d82492ee7300a526adb60eb5c#54f0d1bcf0e1a91d82492ee7300a526adb60eb5c" dependencies = [ "anyhow", "bytemuck", @@ -1837,7 +1838,7 @@ dependencies = [ [[package]] name = "floem_vger_renderer" version = "0.1.1" -source = "git+https://github.com/lapce/floem?rev=48d2b6eb22a02a100d67868052ecc35fa3c42e10#48d2b6eb22a02a100d67868052ecc35fa3c42e10" +source = "git+https://github.com/lapce/floem?rev=54f0d1bcf0e1a91d82492ee7300a526adb60eb5c#54f0d1bcf0e1a91d82492ee7300a526adb60eb5c" dependencies = [ "anyhow", "floem-vger", diff --git a/Cargo.toml b/Cargo.toml index 18702ae19b..658c97f93d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -76,9 +76,9 @@ lapce-core = { path = "./lapce-core" } lapce-rpc = { path = "./lapce-rpc" } lapce-proxy = { path = "./lapce-proxy" } -floem = { git = "https://github.com/lapce/floem", rev = "48d2b6eb22a02a100d67868052ecc35fa3c42e10", features = ["editor", "serde", "default-image-formats", "rfd-async-std"] } +floem = { git = "https://github.com/lapce/floem", rev = "54f0d1bcf0e1a91d82492ee7300a526adb60eb5c", features = ["editor", "serde", "default-image-formats", "rfd-async-std"] } # floem = { path = "../floem", features = ["editor", "serde", "default-image-formats", "rfd-async-std"] } -floem-editor-core = { git = "https://github.com/lapce/floem", rev = "48d2b6eb22a02a100d67868052ecc35fa3c42e10", features = ["serde"] } +floem-editor-core = { git = "https://github.com/lapce/floem", rev = "54f0d1bcf0e1a91d82492ee7300a526adb60eb5c", features = ["serde"] } # floem-editor-core = { path = "../floem/editor-core/", features = ["serde"] } [patch.crates-io] diff --git a/lapce-app/src/app.rs b/lapce-app/src/app.rs index aaf20ea7e5..4d06464808 100644 --- a/lapce-app/src/app.rs +++ b/lapce-app/src/app.rs @@ -3103,7 +3103,7 @@ fn code_action(window_tab_data: Rc) -> impl View { .align_items(Some(AlignItems::Center)) .min_width(0.0) .width_full() - .line_height(1.6) + .line_height(1.8) .border_radius(6.0) .cursor(CursorStyle::Pointer) .apply_if(active.get() == i, |s| { diff --git a/lapce-app/src/code_action.rs b/lapce-app/src/code_action.rs index 9919ec7103..0db20e3d17 100644 --- a/lapce-app/src/code_action.rs +++ b/lapce-app/src/code_action.rs @@ -1,4 +1,4 @@ -use std::{rc::Rc, sync::Arc}; +use std::rc::Rc; use floem::{ keyboard::Modifiers, @@ -166,7 +166,8 @@ impl CodeActionData { pub fn show( &mut self, - code_actions: Arc<(PluginId, Vec)>, + plugin_id: PluginId, + code_actions: im::Vector, offset: usize, mouse_click: bool, ) { @@ -176,11 +177,10 @@ impl CodeActionData { self.mouse_click = mouse_click; self.request_id += 1; self.items = code_actions - .1 - .iter() + .into_iter() .map(|code_action| ScoredCodeActionItem { - item: code_action.clone(), - plugin_id: code_actions.0, + item: code_action, + plugin_id, score: 0, indices: Vec::new(), }) diff --git a/lapce-app/src/code_lens.rs b/lapce-app/src/code_lens.rs new file mode 100644 index 0000000000..3dddfd164f --- /dev/null +++ b/lapce-app/src/code_lens.rs @@ -0,0 +1,94 @@ +use std::rc::Rc; + +use lapce_rpc::dap_types::RunDebugConfig; +use serde::{Deserialize, Serialize}; +use serde_json::Value; + +use crate::{command::InternalCommand, debug::RunDebugMode, window_tab::CommonData}; + +#[derive(Serialize, Deserialize)] +struct CargoArgs { + #[serde(rename = "cargoArgs")] + pub cargo_args: Vec, + + #[serde(rename = "cargoExtraArgs")] + pub cargo_extra_args: Vec, + + #[serde(rename = "executableArgs")] + pub executable_args: Vec, +} + +#[derive(Serialize, Deserialize)] +struct RustArgs { + pub args: CargoArgs, + pub kind: String, + pub label: String, + pub location: lsp_types::LocationLink, +} + +#[derive(Clone)] +pub struct CodeLensData { + common: Rc, +} + +impl CodeLensData { + pub fn new(common: Rc) -> Self { + Self { common } + } + + pub fn run(&self, command: &str, args: Vec) { + match command { + "rust-analyzer.runSingle" | "rust-analyzer.debugSingle" => { + if let Some(config) = self.get_rust_command_config(&args) { + let mode = if command == "rust-analyzer.runSingle" { + RunDebugMode::Run + } else { + RunDebugMode::Debug + }; + self.common + .internal_command + .send(InternalCommand::RunAndDebug { mode, config }); + } + } + _ => { + tracing::debug!("todo {:}", command); + } + } + } + + fn get_rust_command_config(&self, args: &[Value]) -> Option { + if let Some(args) = args.first() { + let Ok(mut cargo_args) = + serde_json::from_value::(args.clone()) + else { + tracing::error!("serde error"); + return None; + }; + cargo_args + .args + .cargo_args + .extend(cargo_args.args.cargo_extra_args); + if !cargo_args.args.executable_args.is_empty() { + cargo_args.args.cargo_args.push("--".to_string()); + cargo_args + .args + .cargo_args + .extend(cargo_args.args.executable_args); + } + Some(RunDebugConfig { + ty: None, + name: cargo_args.label, + program: cargo_args.kind, + args: Some(cargo_args.args.cargo_args), + cwd: None, + env: None, + prelaunch: None, + debug_command: None, + dap_id: Default::default(), + }) + } else { + tracing::error!("no args"); + None + } + } +} diff --git a/lapce-app/src/command.rs b/lapce-app/src/command.rs index 1dcc564159..1ea715861c 100644 --- a/lapce-app/src/command.rs +++ b/lapce-app/src/command.rs @@ -1,4 +1,4 @@ -use std::{path::PathBuf, rc::Rc, sync::Arc}; +use std::{path::PathBuf, rc::Rc}; pub use floem::views::editor::command::CommandExecuted; use floem::{ @@ -649,7 +649,8 @@ pub enum InternalCommand { ShowCodeActions { offset: usize, mouse_click: bool, - code_actions: Arc<(PluginId, Vec)>, + plugin_id: PluginId, + code_actions: im::Vector, }, RunCodeAction { plugin_id: PluginId, diff --git a/lapce-app/src/doc.rs b/lapce-app/src/doc.rs index ad5d386485..cd64958b1c 100644 --- a/lapce-app/src/doc.rs +++ b/lapce-app/src/doc.rs @@ -64,7 +64,8 @@ use lapce_xi_rope::{ Interval, Rope, RopeDelta, Transformer, }; use lsp_types::{ - CodeActionResponse, Diagnostic, DiagnosticSeverity, InlayHint, InlayHintLabel, + CodeActionOrCommand, CodeLens, Diagnostic, DiagnosticSeverity, InlayHint, + InlayHintLabel, }; use serde::{Deserialize, Serialize}; use smallvec::SmallVec; @@ -76,7 +77,7 @@ use crate::{ find::{Find, FindProgress, FindResult}, history::DocumentHistory, keypress::KeyPressFocus, - main_split::{Editors, ScoredCodeLensItem}, + main_split::Editors, panel::kind::PanelKind, window_tab::{CommonData, Focus}, workspace::LapceWorkspace, @@ -150,9 +151,10 @@ pub struct DocInfo { } /// (Offset -> (Plugin the code actions are from, Code Actions)) -pub type CodeActions = im::HashMap>; +pub type CodeActions = + im::HashMap)>; -pub type CodeLens = im::HashMap>>; +pub type AllCodeLens = im::HashMap)>; #[derive(Clone)] pub struct Doc { @@ -182,7 +184,7 @@ pub struct Doc { /// (Offset -> (Plugin the code actions are from, Code Actions)) pub code_actions: RwSignal, - pub code_lens: RwSignal, + pub code_lens: RwSignal, /// Stores information about different versions of the document from source control. histories: RwSignal>, @@ -861,43 +863,39 @@ impl Doc { pub fn get_code_lens(&self) { let cx = self.scope; let doc = self.clone(); + self.code_lens.update(|code_lens| { + code_lens.clear(); + }); + let rev = self.rev(); if let DocContent::File { path, .. } = doc.content.get_untracked() { let send = create_ext_action(cx, move |result| { + if rev != doc.rev() { + return; + } if let Ok(ProxyResponse::GetCodeLensResponse { plugin_id, resp }) = result { let Some(codelens) = resp else { return; }; - if codelens.is_empty() { - doc.code_lens.update(|x| { - x.remove(&plugin_id); - }); - } else { - let codelens = codelens - .into_iter() - .filter_map(|x| { - tracing::debug!("{:?}", x); - if let Some(command) = x.command { - if let Some(args) = command.arguments { - Some(Arc::new(ScoredCodeLensItem { - range: x.range, - title: command.title, - command: command.command, - args, - })) - } else { - None - } - } else { - None - } - }) - .collect(); - doc.code_lens.update(|x| { - x.insert(plugin_id, codelens); - }); - } + doc.code_lens.update(|code_lens| { + for codelens in codelens { + let entry = code_lens + .entry(codelens.range.start.line as usize) + .or_insert_with(|| { + ( + plugin_id, + doc.buffer.with_untracked(|b| { + b.offset_of_line( + codelens.range.start.line as usize, + ) + }), + im::Vector::new(), + ) + }); + entry.2.push_back(codelens); + } + }); } }); self.common.proxy.get_code_lens(path, move |result| { diff --git a/lapce-app/src/editor.rs b/lapce-app/src/editor.rs index 8b2bebdc11..bf7655523e 100644 --- a/lapce-app/src/editor.rs +++ b/lapce-app/src/editor.rs @@ -47,9 +47,9 @@ use lapce_core::{ use lapce_rpc::{buffer::BufferId, plugin::PluginId, proxy::ProxyResponse}; use lapce_xi_rope::{Rope, RopeDelta, Transformer}; use lsp_types::{ - CompletionItem, CompletionTextEdit, GotoDefinitionResponse, HoverContents, - InlayHint, InlayHintLabel, InlineCompletionTriggerKind, Location, MarkedString, - MarkupKind, Range, TextEdit, + CodeActionResponse, CompletionItem, CompletionTextEdit, GotoDefinitionResponse, + HoverContents, InlayHint, InlayHintLabel, InlineCompletionTriggerKind, Location, + MarkedString, MarkupKind, Range, TextEdit, }; use serde::{Deserialize, Serialize}; @@ -2019,7 +2019,7 @@ impl EditorData { // insert some empty data, so that we won't make the request again doc.code_actions().update(|c| { - c.insert(offset, Arc::new((PluginId(0), Vec::new()))); + c.insert(offset, (PluginId(0), im::Vector::new())); }); let (position, rev, diagnostics) = doc.buffer.with_untracked(|buffer| { @@ -2041,13 +2041,16 @@ impl EditorData { (position, rev, diagnostics) }); - let send = create_ext_action(self.scope, move |resp| { - if doc.rev() == rev { - doc.code_actions().update(|c| { - c.insert(offset, Arc::new(resp)); - }); - } - }); + let send = create_ext_action( + self.scope, + move |resp: (PluginId, CodeActionResponse)| { + if doc.rev() == rev { + doc.code_actions().update(|c| { + c.insert(offset, (resp.0, resp.1.into())); + }); + } + }, + ); self.common.proxy.get_code_actions( path, @@ -2071,12 +2074,13 @@ impl EditorData { let code_actions = doc .code_actions() .with_untracked(|c| c.get(&offset).cloned()); - if let Some(code_actions) = code_actions { - if !code_actions.1.is_empty() { + if let Some((plugin_id, code_actions)) = code_actions { + if !code_actions.is_empty() { self.common.internal_command.send( InternalCommand::ShowCodeActions { offset, mouse_click, + plugin_id, code_actions, }, ); diff --git a/lapce-app/src/editor/gutter.rs b/lapce-app/src/editor/gutter.rs index 0576de2d88..373ab81de1 100644 --- a/lapce-app/src/editor/gutter.rs +++ b/lapce-app/src/editor/gutter.rs @@ -1,6 +1,7 @@ use floem::{ context::PaintCx, peniko::kurbo::{Point, Rect, Size}, + reactive::Memo, text::{Attrs, AttrsList, FamilyOwned, TextLayout}, Renderer, View, ViewId, }; @@ -13,15 +14,20 @@ pub struct EditorGutterView { id: ViewId, editor: EditorData, width: f64, + gutter_padding_right: Memo, } -pub fn editor_gutter_view(editor: EditorData) -> EditorGutterView { +pub fn editor_gutter_view( + editor: EditorData, + gutter_padding_right: Memo, +) -> EditorGutterView { let id = ViewId::new(); EditorGutterView { id, editor, width: 0.0, + gutter_padding_right, } } @@ -40,6 +46,7 @@ impl EditorGutterView { let changes = e_data.doc().head_changes().get_untracked(); let line_height = config.editor.line_height() as f64; + let gutter_padding_right = self.gutter_padding_right.get_untracked() as f64; let changes = changes_colors_screen(config, &e_data.editor, changes); for (y, height, removed, color) in changes { @@ -53,9 +60,10 @@ impl EditorGutterView { y -= 5.0; } cx.fill( - &Size::new(3.0, height) - .to_rect() - .with_origin(Point::new(self.width + 7.0, y)), + &Size::new(3.0, height).to_rect().with_origin(Point::new( + self.width + 5.0 - gutter_padding_right, + y, + )), color, 0.0, ) @@ -176,7 +184,10 @@ impl View for EditorGutterView { cx.draw_text( &text_layout, Point::new( - (self.width - (size.width)).max(0.0), + (self.width + - size.width + - self.gutter_padding_right.get_untracked() as f64) + .max(0.0), y + (line_height - height) / 2.0 - viewport.y0, ), ); diff --git a/lapce-app/src/editor/view.rs b/lapce-app/src/editor/view.rs index dc3e02c444..df80fc1478 100644 --- a/lapce-app/src/editor/view.rs +++ b/lapce-app/src/editor/view.rs @@ -1,7 +1,7 @@ -use std::{cmp, path::PathBuf, rc::Rc, sync::Arc}; +use std::{cmp, collections::BTreeMap, path::PathBuf, rc::Rc, sync::Arc}; use floem::{ - action::{add_overlay, set_ime_allowed, set_ime_cursor_area}, + action::{set_ime_allowed, set_ime_cursor_area}, context::{PaintCx, StyleCx}, event::{Event, EventListener, EventPropagation}, keyboard::Modifiers, @@ -12,7 +12,7 @@ use floem::{ reactive::{ create_effect, create_memo, create_rw_signal, Memo, ReadSignal, RwSignal, }, - style::{AlignItems, CursorColor, CursorStyle, Style, TextColor}, + style::{CursorColor, CursorStyle, Style, TextColor}, taffy::prelude::NodeId, views::{ clip, container, dyn_stack, @@ -31,29 +31,31 @@ use floem::{ }, empty, label, scroll::{scroll, HideBar, PropagatePointerWheel}, - stack, svg, text, Decorators, + stack, svg, Decorators, }, Renderer, View, ViewId, }; -use im::Vector; use itertools::Itertools; use lapce_core::{ buffer::{diff::DiffLines, rope_text::RopeText, Buffer}, cursor::{CursorAffinity, CursorMode}, }; -use lapce_rpc::dap_types::{DapId, SourceBreakpoint}; +use lapce_rpc::{ + dap_types::{DapId, SourceBreakpoint}, + plugin::PluginId, +}; use lapce_xi_rope::find::CaseMatching; +use lsp_types::CodeLens; use super::{gutter::editor_gutter_view, DocSignal, EditorData}; use crate::{ app::clickable_icon, command::InternalCommand, config::{color::LapceColor, editor::WrapStyle, icon::LapceIcons, LapceConfig}, - debug::LapceBreakpoint, + debug::{DapData, LapceBreakpoint}, doc::DocContent, - main_split::ScoredCodeLensItem, text_input::TextInputBuilder, - window_tab::{Focus, WindowTabData}, + window_tab::{CommonData, Focus, WindowTabData}, workspace::LapceWorkspace, }; @@ -1263,7 +1265,7 @@ pub fn editor_container_view( stack(( editor_breadcrumbs(workspace, editor.get_untracked(), config), stack(( - editor_gutter(window_tab_data.clone(), editor, is_active), + editor_gutter(window_tab_data.clone(), editor), editor_content(editor, debug_breakline, is_active), empty().style(move |s| { let config = config.get(); @@ -1323,22 +1325,123 @@ pub fn editor_container_view( .debug_name("Editor Container") } -fn editor_gutter( +fn editor_gutter_breakpoint_view( + i: usize, + doc: DocSignal, + daps: RwSignal>, + breakpoints: RwSignal>>, + screen_lines: RwSignal, + common: Rc, + icon_padding: f32, +) -> impl View { + let hovered = create_rw_signal(false); + let config = common.config; + container( + svg(move || config.get().ui_svg(LapceIcons::DEBUG_BREAKPOINT)).style( + move |s| { + let config = config.get(); + let size = config.ui.icon_size() as f32 + 2.0; + s.size(size, size) + .color(config.color(LapceColor::DEBUG_BREAKPOINT_HOVER)) + .apply_if(!hovered.get(), |s| s.hide()) + }, + ), + ) + .on_click_stop(move |_| { + let screen_lines = screen_lines.get_untracked(); + let line = screen_lines.lines.get(i).map(|r| r.line).unwrap_or(0); + // let line = (viewport.get_untracked().y0 + // / config.get_untracked().editor.line_height() as f64) + // .floor() as usize + // + i; + let doc = doc.get_untracked(); + let offset = doc.buffer.with_untracked(|b| b.offset_of_line(line)); + if let Some(path) = doc.content.get_untracked().path() { + let path_breakpoints = breakpoints + .try_update(|breakpoints| { + let breakpoints = breakpoints.entry(path.clone()).or_default(); + if let std::collections::btree_map::Entry::Vacant(e) = + breakpoints.entry(line) + { + e.insert(LapceBreakpoint { + id: None, + verified: false, + message: None, + line, + offset, + dap_line: None, + active: true, + }); + } else { + let mut toggle_active = false; + if let Some(breakpint) = breakpoints.get_mut(&line) { + if !breakpint.active { + breakpint.active = true; + toggle_active = true; + } + } + if !toggle_active { + breakpoints.remove(&line); + } + } + breakpoints.clone() + }) + .unwrap(); + let source_breakpoints: Vec = path_breakpoints + .iter() + .filter_map(|(_, b)| { + if b.active { + Some(SourceBreakpoint { + line: b.line + 1, + column: None, + condition: None, + hit_condition: None, + log_message: None, + }) + } else { + None + } + }) + .collect(); + let daps: Vec = + daps.with_untracked(|daps| daps.keys().cloned().collect()); + for dap_id in daps { + common.proxy.dap_set_breakpoints( + dap_id, + path.to_path_buf(), + source_breakpoints.clone(), + ); + } + } + }) + .on_event_stop(EventListener::PointerEnter, move |_| { + hovered.set(true); + }) + .on_event_stop(EventListener::PointerLeave, move |_| { + hovered.set(false); + }) + .style(move |s| { + let config = config.get(); + s.width(config.ui.icon_size() as f32 + icon_padding * 2.0) + .height(config.editor.line_height() as f32) + .justify_center() + .items_center() + .cursor(CursorStyle::Pointer) + }) +} + +fn editor_gutter_breakpoints( window_tab_data: Rc, e_data: RwSignal, - is_active: impl Fn(bool) -> bool + 'static + Copy, + icon_padding: f32, ) -> impl View { let breakpoints = window_tab_data.terminal.debug.breakpoints; let daps = window_tab_data.terminal.debug.daps; - - let padding_left = 25.0; - let padding_right = 30.0; + let common = window_tab_data.common.clone(); let (ed, doc, config) = e_data .with_untracked(|e| (e.editor.clone(), e.doc_signal(), e.common.config)); - let cursor = ed.cursor; let viewport = ed.viewport; - let scroll_delta = ed.scroll_delta; let screen_lines = ed.screen_lines; let num_display_lines = create_memo(move |_| { @@ -1349,262 +1452,306 @@ fn editor_gutter( // (viewport.height() / line_height).ceil() as usize + 1 }); - let code_action_vline = create_memo(move |_| { - if is_active(true) { + clip( + stack(( + dyn_stack( + move || { + let num = num_display_lines.get(); + 0..num + }, + move |i| *i, + move |i| { + editor_gutter_breakpoint_view( + i, + doc, + daps, + breakpoints, + screen_lines, + common.clone(), + icon_padding, + ) + }, + ) + .style(move |s| { + s.absolute().flex_col().margin_top( + -(viewport.get().y0 % config.get().editor.line_height() as f64) + as f32, + ) + }) + .debug_name("Breakpoint Stack"), + dyn_stack( + move || { + let e_data = e_data.get(); + let doc = e_data.doc_signal().get(); + let content = doc.content.get(); + let breakpoints = if let Some(path) = content.path() { + breakpoints + .with(|b| b.get(path).cloned()) + .unwrap_or_default() + } else { + Default::default() + }; + breakpoints.into_iter() + }, + move |(line, b)| (*line, b.active), + move |(line, breakpoint)| { + let active = breakpoint.active; + container( + svg(move || { + config.get().ui_svg(LapceIcons::DEBUG_BREAKPOINT) + }) + .style(move |s| { + let config = config.get(); + let size = config.ui.icon_size() as f32 + 2.0; + let color = if active { + LapceColor::DEBUG_BREAKPOINT + } else { + LapceColor::EDITOR_DIM + }; + let color = config.color(color); + s.size(size, size).color(color) + }), + ) + .style(move |s| { + let config = config.get(); + let line_y = screen_lines + .with(|s| s.info_for_line(line)) + .map(|l| l.y) + .unwrap_or_default(); + s.absolute() + .width(config.ui.icon_size() as f32 + icon_padding * 2.0) + .height(config.editor.line_height() as f32) + .justify_center() + .items_center() + .margin_top(line_y as f32 - viewport.get().y0 as f32) + }) + }, + ) + .style(|s| s.absolute().size_pct(100.0, 100.0)), + )) + .style(|s| s.size_pct(100.0, 100.0)), + ) + .style(move |s| { + s.absolute() + .size_pct(100.0, 100.0) + .background(config.get().color(LapceColor::EDITOR_BACKGROUND)) + }) +} + +fn editor_gutter_code_lens_view( + window_tab_data: Rc, + line: usize, + lens: (PluginId, usize, im::Vector), + screen_lines: RwSignal, + viewport: RwSignal, + icon_padding: f32, +) -> impl View { + let config = window_tab_data.common.config; + let view = container(svg(move || config.get().ui_svg(LapceIcons::START)).style( + move |s| { + let config = config.get(); + let size = config.ui.icon_size() as f32; + s.size(size, size) + .color(config.color(LapceColor::LAPCE_ICON_ACTIVE)) + }, + )) + .style(move |s| { + let config = config.get(); + s.padding(4.0) + .border_radius(6.0) + .hover(|s| { + s.cursor(CursorStyle::Pointer) + .background(config.color(LapceColor::PANEL_HOVERED_BACKGROUND)) + }) + .active(|s| { + s.background( + config.color(LapceColor::PANEL_HOVERED_ACTIVE_BACKGROUND), + ) + }) + }) + .on_click_stop({ + move |_| { + let (plugin_id, offset, lens) = lens.clone(); + window_tab_data.show_code_lens(true, plugin_id, offset, lens); + } + }); + container(view).style(move |s| { + let line_info = screen_lines.with(|s| s.info_for_line(line)); + let line_y = line_info.clone().map(|l| l.y).unwrap_or(-100.0); + let rect = viewport.get(); + let config = config.get(); + let icon_size = config.ui.icon_size(); + let width = icon_size as f32 + icon_padding * 2.0; + s.absolute() + .width(width) + .height(config.editor.line_height() as f32) + .justify_center() + .items_center() + .margin_top(line_y as f32 - rect.y0 as f32) + }) +} + +fn editor_gutter_code_lens( + window_tab_data: Rc, + doc: DocSignal, + screen_lines: RwSignal, + viewport: RwSignal, + icon_padding: f32, +) -> impl View { + let config = window_tab_data.common.config; + + dyn_stack( + move || { let doc = doc.get(); - let (offset, affinity) = - cursor.with(|cursor| (cursor.offset(), cursor.affinity)); - let has_code_actions = doc - .code_actions() - .with(|c| c.get(&offset).map(|c| !c.1.is_empty()).unwrap_or(false)); - if has_code_actions { - let vline = ed.vline_of_offset(offset, affinity); - Some(vline) - } else { - None - } + doc.code_lens.get() + }, + move |(line, _)| (*line, doc.with_untracked(|doc| doc.rev())), + move |(line, lens)| { + editor_gutter_code_lens_view( + window_tab_data.clone(), + line, + lens, + screen_lines, + viewport, + icon_padding, + ) + }, + ) + .style(move |s| { + let config = config.get(); + let width = config.ui.icon_size() as f32 + icon_padding * 2.0; + s.absolute() + .width(width) + .height_full() + .margin_left(width - 8.0) + }) + .debug_name("CodeLens Stack") +} + +fn editor_gutter_code_actions( + e_data: RwSignal, + gutter_width: Memo, + icon_padding: f32, +) -> impl View { + let (ed, doc, config) = e_data + .with_untracked(|e| (e.editor.clone(), e.doc_signal(), e.common.config)); + let viewport = ed.viewport; + let cursor = ed.cursor; + + let code_action_vline = create_memo(move |_| { + let doc = doc.get(); + let (offset, affinity) = + cursor.with(|cursor| (cursor.offset(), cursor.affinity)); + let has_code_actions = doc + .code_actions() + .with(|c| c.get(&offset).map(|c| !c.1.is_empty()).unwrap_or(false)); + if has_code_actions { + let vline = ed.vline_of_offset(offset, affinity); + Some(vline) } else { None } }); - let gutter_rect = create_rw_signal(Rect::ZERO); - let gutter_width = create_memo(move |_| gutter_rect.get().width()); - - let breakpoints_view = move |i: usize| { - let hovered = create_rw_signal(false); + container( container( - svg(move || config.get().ui_svg(LapceIcons::DEBUG_BREAKPOINT)).style( + svg(move || config.get().ui_svg(LapceIcons::LIGHTBULB)).style( move |s| { let config = config.get(); - let size = config.ui.icon_size() as f32 + 2.0; + let size = config.ui.icon_size() as f32; s.size(size, size) - .color(config.color(LapceColor::DEBUG_BREAKPOINT_HOVER)) - .apply_if(!hovered.get(), |s| s.hide()) + .color(config.color(LapceColor::LAPCE_WARN)) }, ), ) .on_click_stop(move |_| { - let screen_lines = screen_lines.get_untracked(); - let line = screen_lines.lines.get(i).map(|r| r.line).unwrap_or(0); - // let line = (viewport.get_untracked().y0 - // / config.get_untracked().editor.line_height() as f64) - // .floor() as usize - // + i; - let e_data = e_data.get_untracked(); - let doc = e_data.doc(); - let offset = doc.buffer.with_untracked(|b| b.offset_of_line(line)); - if let Some(path) = doc.content.get_untracked().path() { - let path_breakpoints = breakpoints - .try_update(|breakpoints| { - let breakpoints = - breakpoints.entry(path.clone()).or_default(); - if let std::collections::btree_map::Entry::Vacant(e) = - breakpoints.entry(line) - { - e.insert(LapceBreakpoint { - id: None, - verified: false, - message: None, - line, - offset, - dap_line: None, - active: true, - }); - } else { - let mut toggle_active = false; - if let Some(breakpint) = breakpoints.get_mut(&line) { - if !breakpint.active { - breakpint.active = true; - toggle_active = true; - } - } - if !toggle_active { - breakpoints.remove(&line); - } - } - breakpoints.clone() - }) - .unwrap(); - let source_breakpoints: Vec = path_breakpoints - .iter() - .filter_map(|(_, b)| { - if b.active { - Some(SourceBreakpoint { - line: b.line + 1, - column: None, - condition: None, - hit_condition: None, - log_message: None, - }) - } else { - None - } - }) - .collect(); - let daps: Vec = - daps.with_untracked(|daps| daps.keys().cloned().collect()); - for dap_id in daps { - e_data.common.proxy.dap_set_breakpoints( - dap_id, - path.to_path_buf(), - source_breakpoints.clone(), - ); - } - } - }) - .on_event_stop(EventListener::PointerEnter, move |_| { - hovered.set(true); - }) - .on_event_stop(EventListener::PointerLeave, move |_| { - hovered.set(false); + e_data.get_untracked().show_code_actions(true); }) .style(move |s| { - s.width(padding_left) - .height(config.get().editor.line_height() as f32) - .justify_center() - .items_center() - .cursor(CursorStyle::Pointer) - }) - }; + let config = config.get(); + s.padding(4.0) + .border_radius(6.0) + .hover(|s| { + s.cursor(CursorStyle::Pointer).background( + config.color(LapceColor::PANEL_HOVERED_BACKGROUND), + ) + }) + .active(|s| { + s.background( + config.color(LapceColor::PANEL_HOVERED_ACTIVE_BACKGROUND), + ) + }) + }), + ) + .style(move |s| { + let config = config.get(); + let viewport = viewport.get(); + let gutter_width = gutter_width.get(); + let code_action_vline = code_action_vline.get(); + let size = config.ui.icon_size() as f32; + let line_height = config.editor.line_height(); + let margin_top = if let Some(vline) = code_action_vline { + (vline.get() * line_height) as f32 - viewport.y0 as f32 + } else { + 0.0 + }; + let width = size + icon_padding * 2.0; + s.absolute() + .items_center() + .justify_center() + .margin_left(gutter_width as f32 - width + 1.0) + .margin_top(margin_top) + .width(width) + .height(line_height as f32) + .apply_if(code_action_vline.is_none(), |s| s.hide()) + }) + .debug_name("Code Action LightBulb") +} - let code_lens_view = { - let window_tab_data = window_tab_data.clone(); - move |(line, lens): (usize, Vector>)| { - let window_tab_data = window_tab_data.clone(); - let view = container( - svg(move || config.get().ui_svg(LapceIcons::START)).style( - move |s| { - let config = config.get(); - let size = config.ui.icon_size() as f32 + 2.0; - s.size(size, size) - .color(config.color(LapceColor::LAPCE_ICON_ACTIVE)) - }, - ), - ); - let id = view.id(); - view.on_click_stop({ - let window_tab_data = window_tab_data.clone(); - let lens = lens.clone(); - move |event| { - if let Event::PointerUp(_) = event { - let window_tab = window_tab_data.clone(); - let rec = id.layout_rect(); - let line_height = - config.get_untracked().editor.line_height() as f64; - let pos = Point::new(rec.x1, rec.y0 + line_height); - let lens = lens.clone(); - let view_id = add_overlay(pos, move |_| { - code_lens(window_tab.clone(), lens) - }); - window_tab_data.update_code_lens_id(Some(view_id)); - } - } - }) - .style(move |s| { - let line_info = screen_lines.with(|s| s.info_for_line(line)); - let line_y = line_info.clone().map(|l| l.y).unwrap_or(-100.0); - let rect = viewport.get(); - let config = config.get(); - s.absolute() - .width(padding_right) - .height(config.editor.line_height() as f32) - .justify_center() - .items_center() - .margin_top(line_y as f32 - rect.y0 as f32) - }) - } +fn editor_gutter( + window_tab_data: Rc, + e_data: RwSignal, +) -> impl View { + let icon_padding = 6.0; + + let (ed, doc, config) = e_data + .with_untracked(|e| (e.editor.clone(), e.doc_signal(), e.common.config)); + let viewport = ed.viewport; + let scroll_delta = ed.scroll_delta; + let screen_lines = ed.screen_lines; + + let gutter_rect = create_rw_signal(Rect::ZERO); + let gutter_width = create_memo(move |_| gutter_rect.get().width()); + + let icon_total_width = move || { + let icon_size = config.get().ui.icon_size() as f32; + icon_size + icon_padding * 2.0 }; + let gutter_padding_right = create_memo(move |_| icon_total_width() + 6.0); + stack(( stack(( - empty().style(move |s| s.width(padding_left)), + empty().style(move |s| s.width(icon_total_width() * 2.0 - 8.0)), label(move || { let doc = doc.get(); doc.buffer.with(|b| b.last_line() + 1).to_string() }), - empty().style(move |s| s.width(padding_right)), + empty().style(move |s| s.width(gutter_padding_right.get())), )) .debug_name("Centered Last Line Count") .style(|s| s.height_pct(100.0)), + editor_gutter_breakpoints(window_tab_data.clone(), e_data, icon_padding), clip( stack(( - dyn_stack( - move || { - let num = num_display_lines.get(); - 0..num - }, - move |i| *i, - breakpoints_view, - ) - .style(move |s| { - s.absolute().flex_col().margin_top( - -(viewport.get().y0 - % config.get().editor.line_height() as f64) - as f32, - ) - }) - .debug_name("Breakpoint Stack"), - dyn_stack( - move || { - let e_data = e_data.get(); - let doc = e_data.doc_signal().get(); - let content = doc.content.get(); - let breakpoints = if let Some(path) = content.path() { - breakpoints - .with(|b| b.get(path).cloned()) - .unwrap_or_default() - } else { - Default::default() - }; - breakpoints.into_iter() - }, - move |(line, b)| (*line, b.active), - move |(line, breakpoint)| { - let active = breakpoint.active; - let line_y = screen_lines - .with_untracked(|s| s.info_for_line(line)) - .map(|l| l.y) - .unwrap_or_default(); - container( - svg(move || { - config.get().ui_svg(LapceIcons::DEBUG_BREAKPOINT) - }) - .style(move |s| { - let config = config.get(); - let size = config.ui.icon_size() as f32 + 2.0; - let color = if active { - LapceColor::DEBUG_BREAKPOINT - } else { - LapceColor::EDITOR_DIM - }; - let color = config.color(color); - s.size(size, size).color(color) - }), - ) - .style(move |s| { - let config = config.get(); - s.absolute() - .width(padding_left) - .height(config.editor.line_height() as f32) - .justify_center() - .items_center() - .margin_top(line_y as f32 - viewport.get().y0 as f32) - }) - }, - ) - .style(|s| s.absolute().size_pct(100.0, 100.0)), - )) - .style(|s| s.size_pct(100.0, 100.0)), - ) - .style(move |s| { - s.absolute() - .size_pct(100.0, 100.0) - .background(config.get().color(LapceColor::EDITOR_BACKGROUND)) - }), - clip( - stack(( - editor_gutter_view(e_data.get_untracked()) + editor_gutter_code_lens( + window_tab_data.clone(), + doc, + screen_lines, + viewport, + icon_padding, + ), + editor_gutter_view(e_data.get_untracked(), gutter_padding_right) .on_resize(move |rect| { gutter_rect.set(rect); }) @@ -1614,93 +1761,11 @@ fn editor_gutter( } }) .style(|s| s.size_pct(100.0, 100.0)), - dyn_stack( - move || { - let doc = doc.get(); - doc.code_lens.with(|x| { - let mut lines = im::HashMap::< - usize, - Vector>, - >::new(); - for (_, lens) in x.iter() { - for item in lens { - lines - .entry(item.range.start.line as usize) - .or_default() - .push_back(item.clone()); - } - } - lines - }) - }, - move |i| i.0, - code_lens_view, - ) - .style(move |s| { - let gutter_width = gutter_width.get(); - s.absolute() - .size_pct(100.0, 100.0) - .margin_left(gutter_width) - }) - .debug_name("CodeLens Stack"), - container( - svg(move || config.get().ui_svg(LapceIcons::LIGHTBULB)).style( - move |s| { - let config = config.get(); - let size = config.ui.icon_size() as f32; - s.size(size, size) - .color(config.color(LapceColor::LAPCE_WARN)) - }, - ), - ) - .on_click_stop(move |_| { - e_data.get_untracked().show_code_actions(true); - }) - .style(move |s| { - let config = config.get(); - let viewport = viewport.get(); - let gutter_width = gutter_width.get(); - let code_action_vline = code_action_vline.get(); - let size = config.ui.icon_size() as f32; - let margin_left = - gutter_width as f32 + (padding_right - size) / 2.0 - 4.0; - let line_height = config.editor.line_height(); - let margin_top = if let Some(vline) = code_action_vline { - (vline.get() * line_height) as f32 - viewport.y0 as f32 - + (line_height as f32 - size) / 2.0 - - 4.0 - } else { - 0.0 - }; - s.absolute() - .padding(4.0) - .border_radius(6.0) - .margin_left(margin_left) - .margin_top(margin_top) - .apply_if(code_action_vline.is_none(), |s| s.hide()) - .hover(|s| { - s.cursor(CursorStyle::Pointer).background( - config.color(LapceColor::PANEL_HOVERED_BACKGROUND), - ) - }) - .active(|s| { - s.background( - config.color( - LapceColor::PANEL_HOVERED_ACTIVE_BACKGROUND, - ), - ) - }) - }) - .debug_name("Code Action LightBulb"), + editor_gutter_code_actions(e_data, gutter_width, icon_padding), )) .style(|s| s.size_pct(100.0, 100.0)), ) - .style(move |s| { - s.absolute() - .size_pct(100.0, 100.0) - .padding_left(padding_left) - .padding_right(padding_right) - }), + .style(move |s| s.absolute().size_pct(100.0, 100.0)), )) .style(|s| s.height_pct(100.0)) .debug_name("Editor Gutter") @@ -2430,64 +2495,3 @@ pub fn changes_colors_all( colors } - -fn code_lens( - window_tab_data: Rc, - code_lens: im::Vector>, -) -> floem::views::Container { - let config = window_tab_data.common.config; - let main_split = window_tab_data.main_split.clone(); - container( - dyn_stack( - move || code_lens.clone().into_iter().enumerate(), - move |(i, _item)| *i, - { - let main_split = main_split.clone(); - let window_tab_data = window_tab_data.clone(); - move |(_, item): (usize, Arc)| { - let value = main_split.clone(); - container( - text(item.title.replace('\n', " ")) - .style(|s| s.text_ellipsis().min_width(0.0)), - ) - .on_click_stop({ - let window_tab_data = window_tab_data.clone(); - move |_| { - window_tab_data.update_code_lens_id(None); - value.run_code_lens(&item.args, &item.command); - } - }) - .on_event_stop(EventListener::PointerDown, |_| {}) - .style(move |s| { - let config = config.get(); - s.padding_horiz(10.0) - .align_items(Some(AlignItems::Center)) - .min_width(0.0) - .width_full() - .line_height(1.6) - .border_radius(6.0) - .cursor(CursorStyle::Pointer) - .hover(move |s| { - s.background( - config - .color(LapceColor::PANEL_HOVERED_BACKGROUND), - ) - }) - }) - } - }, - ) - .style(|s| s.width_full().flex_col()), - ) - .style(move |s| { - let config = config.get(); - let color = config.color(LapceColor::COMPLETION_BACKGROUND); - s.width(400.0) - .max_height(400.0) - .padding_vert(4.0) - .background(color) - .border_radius(6.0) - }) - .on_event_stop(EventListener::PointerMove, |_| {}) - .debug_name("Code Lens Layer 11") -} diff --git a/lapce-app/src/file_explorer/view.rs b/lapce-app/src/file_explorer/view.rs index e78e391e70..752497699d 100644 --- a/lapce-app/src/file_explorer/view.rs +++ b/lapce-app/src/file_explorer/view.rs @@ -89,7 +89,7 @@ pub fn file_explorer_panel( container( new_file_node_view(data, source_control).style(|s| s.absolute()), ) - .style(|s| s.size_full().line_height(1.6)), + .style(|s| s.size_full().line_height(1.8)), window_tab_data .panel .section_open(PanelSection::FileExplorer), @@ -560,6 +560,6 @@ fn open_editors_view(window_tab_data: Rc) -> impl View { ) .style(|s| s.flex_col().width_pct(100.0)), ) - .style(|s| s.absolute().size_full().line_height(1.6)) + .style(|s| s.absolute().size_full().line_height(1.8)) .debug_name("Open Editors") } diff --git a/lapce-app/src/lib.rs b/lapce-app/src/lib.rs index 2b511e9fbb..43a55cee4d 100644 --- a/lapce-app/src/lib.rs +++ b/lapce-app/src/lib.rs @@ -2,6 +2,7 @@ pub mod about; pub mod alert; pub mod app; pub mod code_action; +pub mod code_lens; pub mod command; pub mod completion; pub mod config; diff --git a/lapce-app/src/main_split.rs b/lapce-app/src/main_split.rs index 9819a0c834..01f696bc11 100644 --- a/lapce-app/src/main_split.rs +++ b/lapce-app/src/main_split.rs @@ -20,23 +20,22 @@ use lapce_core::{ }; use lapce_rpc::{ buffer::BufferId, - dap_types::RunDebugConfig, plugin::{PluginId, VoltID}, proxy::ProxyResponse, }; use lapce_xi_rope::{spans::SpansBuilder, Rope}; use lsp_types::{ CodeAction, CodeActionOrCommand, DiagnosticSeverity, DocumentChangeOperation, - DocumentChanges, OneOf, Position, Range, TextEdit, Url, WorkspaceEdit, + DocumentChanges, OneOf, Position, TextEdit, Url, WorkspaceEdit, }; use serde::{Deserialize, Serialize}; use serde_json::Value; -use tracing::{debug, error, event, Level}; +use tracing::{event, Level}; use crate::{ alert::AlertButton, + code_lens::CodeLensData, command::InternalCommand, - debug::RunDebugMode, doc::{DiagnosticData, Doc, DocContent, DocHistory, EditorDiagnostic}, editor::{ diff::DiffEditorData, @@ -388,6 +387,7 @@ pub struct MainSplitData { pub locations: RwSignal>, pub current_location: RwSignal, pub width: RwSignal, + pub code_lens: RwSignal, pub common: Rc, } @@ -470,6 +470,7 @@ impl MainSplitData { locations, current_location, width: cx.create_rw_signal(0.0), + code_lens: cx.create_rw_signal(CodeLensData::new(common.clone())), common, } } @@ -2153,7 +2154,12 @@ impl MainSplitData { pub fn run_code_action(&self, plugin_id: PluginId, action: CodeActionOrCommand) { match action { - CodeActionOrCommand::Command(_) => {} + CodeActionOrCommand::Command(command) => { + self.run_code_lens( + &command.command, + command.arguments.unwrap_or_default(), + ); + } CodeActionOrCommand::CodeAction(action) => { if let Some(edit) = action.edit.as_ref() { self.apply_workspace_edit(edit); @@ -2164,24 +2170,8 @@ impl MainSplitData { } } - pub fn run_code_lens(&self, args: &[Value], command: &str) { - match command { - "rust-analyzer.runSingle" | "rust-analyzer.debugSingle" => { - if let Some(config) = get_rust_command_config(args) { - let mode = if command == "rust-analyzer.runSingle" { - RunDebugMode::Run - } else { - RunDebugMode::Debug - }; - self.common - .internal_command - .send(InternalCommand::RunAndDebug { mode, config }); - } - } - _ => { - debug!("todo {:}", command); - } - } + pub fn run_code_lens(&self, command: &str, args: Vec) { + self.code_lens.get_untracked().run(command, args); } /// Resolve a code action and apply its held workspace edit @@ -3033,66 +3023,3 @@ pub enum TabCloseKind { CloseToLeft, CloseToRight, } - -#[derive(Clone, Debug, PartialEq)] -pub struct ScoredCodeLensItem { - pub range: Range, - pub title: String, - pub command: String, - pub args: Vec, -} - -#[derive(Serialize, Deserialize)] -struct CargoArgs { - #[serde(rename = "cargoArgs")] - pub cargo_args: Vec, - - #[serde(rename = "cargoExtraArgs")] - pub cargo_extra_args: Vec, - - #[serde(rename = "executableArgs")] - pub executable_args: Vec, -} - -#[derive(Serialize, Deserialize)] -struct RustArgs { - pub args: CargoArgs, - pub kind: String, - pub label: String, - pub location: lsp_types::LocationLink, -} - -fn get_rust_command_config(args: &[Value]) -> Option { - if let Some(args) = args.first() { - let Ok(mut cargo_args) = serde_json::from_value::(args.clone()) - else { - error!("serde error"); - return None; - }; - cargo_args - .args - .cargo_args - .extend(cargo_args.args.cargo_extra_args); - if !cargo_args.args.executable_args.is_empty() { - cargo_args.args.cargo_args.push("--".to_string()); - cargo_args - .args - .cargo_args - .extend(cargo_args.args.executable_args); - } - Some(RunDebugConfig { - ty: None, - name: cargo_args.label, - program: cargo_args.kind, - args: Some(cargo_args.args.cargo_args), - cwd: None, - env: None, - prelaunch: None, - debug_command: None, - dap_id: Default::default(), - }) - } else { - error!("no args"); - None - } -} diff --git a/lapce-app/src/panel/global_search_view.rs b/lapce-app/src/panel/global_search_view.rs index 626a09611f..ccbbf0eb68 100644 --- a/lapce-app/src/panel/global_search_view.rs +++ b/lapce-app/src/panel/global_search_view.rs @@ -310,7 +310,7 @@ fn search_result( .style(|s| s.flex_col()) }, ) - .style(|s| s.flex_col().min_width_pct(100.0).line_height(1.6)) + .style(|s| s.flex_col().min_width_pct(100.0).line_height(1.8)) }) .style(|s| s.absolute().size_pct(100.0, 100.0)) }) diff --git a/lapce-app/src/panel/problem_view.rs b/lapce-app/src/panel/problem_view.rs index 5947f9a3ef..1e413b7683 100644 --- a/lapce-app/src/panel/problem_view.rs +++ b/lapce-app/src/panel/problem_view.rs @@ -70,7 +70,7 @@ fn problem_section( ) }, ) - .style(|s| s.flex_col().width_pct(100.0).line_height(1.6)), + .style(|s| s.flex_col().width_pct(100.0).line_height(1.8)), ) .style(|s| s.absolute().size_pct(100.0, 100.0)) }) diff --git a/lapce-app/src/settings.rs b/lapce-app/src/settings.rs index a9df7e3d88..fe845827d5 100644 --- a/lapce-app/src/settings.rs +++ b/lapce-app/src/settings.rs @@ -448,7 +448,7 @@ pub fn settings_view( .style(move |s| { s.width_pct(100.0) .flex_col() - .line_height(1.6) + .line_height(1.8) .font_size(config.get().ui.font_size() as f32 + 1.0) }) }; @@ -666,14 +666,14 @@ fn settings_item_view( .text_ellipsis() .min_width(0.0) .max_width_pct(100.0) - .line_height(1.6) + .line_height(1.8) .font_size(config.get().ui.font_size() as f32 + 1.0) }), stack(( label(move || item.description.clone()).style(move |s| { s.min_width(0.0) .max_width_pct(100.0) - .line_height(1.6) + .line_height(1.8) .apply_if(is_ticked.is_some(), |s| { s.margin_left(config.get().ui.font_size() as f32 + 8.0) }) @@ -700,7 +700,7 @@ fn settings_item_view( container( stack(( checkbox(move || checked.get(), config), - label(|| " ".to_string()).style(|s| s.line_height(1.6)), + label(|| " ".to_string()).style(|s| s.line_height(1.8)), )) .style(|s| s.items_center()), ) diff --git a/lapce-app/src/window_tab.rs b/lapce-app/src/window_tab.rs index 437b052e2f..eef3c443ef 100644 --- a/lapce-app/src/window_tab.rs +++ b/lapce-app/src/window_tab.rs @@ -30,12 +30,16 @@ use lapce_rpc::{ core::CoreNotification, dap_types::RunDebugConfig, file::{Naming, PathObject}, + plugin::PluginId, proxy::{ProxyResponse, ProxyRpcHandler, ProxyStatus}, source_control::FileDiff, terminal::TermId, RpcError, }; -use lsp_types::{Diagnostic, ProgressParams, ProgressToken, ShowMessageParams}; +use lsp_types::{ + CodeActionOrCommand, CodeLens, Diagnostic, ProgressParams, ProgressToken, + ShowMessageParams, +}; use serde_json::Value; use tracing::{debug, error, event, Level}; @@ -342,7 +346,7 @@ impl WindowTabData { let attrs = Attrs::new() .family(&family) .font_size(config.ui.font_size() as f32) - .line_height(LineHeightValue::Normal(1.6)); + .line_height(LineHeightValue::Normal(1.8)); let attrs_list = AttrsList::new(attrs); text_layout.set_text("W", attrs_list); text_layout.size().height @@ -1640,10 +1644,11 @@ impl WindowTabData { InternalCommand::ShowCodeActions { offset, mouse_click, + plugin_id, code_actions, } => { let mut code_action = self.code_action.get_untracked(); - code_action.show(code_actions, offset, mouse_click); + code_action.show(plugin_id, code_actions, offset, mouse_click); self.code_action.set(code_action); } InternalCommand::RunCodeAction { plugin_id, action } => { @@ -2674,6 +2679,28 @@ impl WindowTabData { } } + pub fn show_code_lens( + &self, + mouse_click: bool, + plugin_id: PluginId, + offset: usize, + lens: im::Vector, + ) { + self.common + .internal_command + .send(InternalCommand::ShowCodeActions { + offset, + mouse_click, + plugin_id, + code_actions: lens + .into_iter() + .filter_map(|lens| { + Some(CodeActionOrCommand::Command(lens.command?)) + }) + .collect(), + }); + } + pub fn call_hierarchy_incoming(&self, item_id: ViewId) { let Some(root) = self.call_hierarchy_data.root.get_untracked() else { return;