code action to use context menu

This commit is contained in:
Dongdong Zhou 2022-05-23 13:01:05 +01:00
parent f94d55f629
commit c19f2bf222
4 changed files with 96 additions and 27 deletions

View File

@ -13,8 +13,8 @@
source_control::DiffInfo, style::Style, terminal::TermId,
};
use lsp_types::{
CodeActionResponse, CompletionItem, CompletionResponse, Location, Position,
ProgressParams, PublishDiagnosticsParams, TextEdit,
CodeActionOrCommand, CodeActionResponse, CompletionItem, CompletionResponse,
Location, Position, ProgressParams, PublishDiagnosticsParams, TextEdit,
};
use serde_json::Value;
use strum::{self, EnumMessage, IntoEnumIterator};
@ -405,6 +405,7 @@ pub enum LapceUICommand {
UpdateHover(usize, Arc<Vec<RichText>>),
UpdateCodeActions(PathBuf, u64, usize, CodeActionResponse),
CancelPalette,
RunCodeAction(CodeActionOrCommand),
ShowCodeActions,
CancelCodeActions,
Hide,

View File

@ -4,6 +4,7 @@
use crate::command::{CommandExecuted, CommandKind};
use crate::completion::{CompletionData, CompletionStatus, Snippet};
use crate::config::Config;
use crate::data::LapceData;
use crate::data::{
EditorDiagnostic, InlineFindDirection, LapceEditorData, LapceMainSplitData,
SplitContent,
@ -40,6 +41,7 @@
};
use lapce_core::mode::{Mode, MotionMode};
pub use lapce_core::syntax::Syntax;
use lsp_types::CodeActionOrCommand;
use lsp_types::CompletionTextEdit;
use lsp_types::{
CodeActionResponse, CompletionItem, DiagnosticSeverity, GotoDefinitionResponse,
@ -1628,11 +1630,32 @@ fn run_focus_command(
ShowCodeActions => {
if let Some(actions) = self.current_code_actions() {
if !actions.is_empty() {
ctx.submit_command(Command::new(
LAPCE_UI_COMMAND,
LapceUICommand::ShowCodeActions,
Target::Auto,
));
let mut menu = druid::Menu::new("");
for action in actions.iter() {
let title = match action {
CodeActionOrCommand::Command(c) => c.title.clone(),
CodeActionOrCommand::CodeAction(a) => {
a.title.clone()
}
};
let mut item = druid::MenuItem::new(title);
item = item.command(Command::new(
LAPCE_UI_COMMAND,
LapceUICommand::RunCodeAction(action.clone()),
Target::Widget(*self.main_split.tab_id),
));
menu = menu.entry(item);
}
let offset = self.editor.new_cursor.offset();
let point = self.doc.point_of_offset(
ctx.text(),
offset,
self.config.editor.font_size,
&self.config,
);
let point = ctx.to_window(point);
ctx.show_context_menu::<LapceData>(menu, point);
}
}
}

View File

@ -194,6 +194,7 @@ fn mouse_down(
match mouse_event.button {
MouseButton::Left => {
self.left_click(ctx, mouse_event, editor_data, config);
editor_data.get_code_actions(ctx);
editor_data.cancel_completion();
// TODO: Don't cancel over here, because it would good to allow the user to
// select text inside the hover data
@ -202,6 +203,7 @@ fn mouse_down(
MouseButton::Right => {
self.mouse_hover_timer = TimerToken::INVALID;
self.right_click(ctx, editor_data, mouse_event, config);
editor_data.get_code_actions(ctx);
editor_data.cancel_completion();
editor_data.cancel_hover();
}

View File

@ -1,12 +1,16 @@
use crate::svg::get_svg;
use druid::{
piet::{Text, TextLayout, TextLayoutBuilder},
BoxConstraints, Env, Event, EventCtx, LayoutCtx, LifeCycle, LifeCycleCtx,
PaintCtx, Point, Rect, RenderContext, Size, UpdateCtx, Widget, WidgetId,
piet::{PietText, Text, TextLayout, TextLayoutBuilder},
BoxConstraints, Command, Env, Event, EventCtx, LayoutCtx, LifeCycle,
LifeCycleCtx, PaintCtx, Point, Rect, RenderContext, Size, Target, UpdateCtx,
Widget, WidgetId,
};
use lapce_core::buffer::DiffLines;
use lapce_core::{buffer::DiffLines, command::FocusCommand};
use lapce_data::{
config::LapceTheme,
command::{
CommandKind, LapceCommand, LapceUICommand, LAPCE_COMMAND, LAPCE_UI_COMMAND,
},
config::{Config, LapceTheme},
data::{EditorView, LapceTabData},
editor::{LapceEditorBufferData, Syntax},
};
@ -14,6 +18,7 @@
pub struct LapceEditorGutter {
view_id: WidgetId,
width: f64,
mouse_down_pos: Point,
}
impl LapceEditorGutter {
@ -21,6 +26,7 @@ pub fn new(view_id: WidgetId) -> Self {
Self {
view_id,
width: 0.0,
mouse_down_pos: Point::ZERO,
}
}
}
@ -28,11 +34,39 @@ pub fn new(view_id: WidgetId) -> Self {
impl Widget<LapceTabData> for LapceEditorGutter {
fn event(
&mut self,
_ctx: &mut EventCtx,
_event: &Event,
_data: &mut LapceTabData,
ctx: &mut EventCtx,
event: &Event,
data: &mut LapceTabData,
_env: &Env,
) {
match event {
Event::MouseDown(mouse_event) => {
self.mouse_down_pos = mouse_event.pos;
}
Event::MouseUp(mouse_event) => {
let data = data.editor_view_content(self.view_id);
if let Some(actions) = data.current_code_actions() {
if !actions.is_empty() {
let rect = self.code_actions_rect(ctx.text(), &data);
if rect.contains(self.mouse_down_pos)
&& rect.contains(mouse_event.pos)
{
ctx.submit_command(Command::new(
LAPCE_COMMAND,
LapceCommand {
kind: CommandKind::Focus(
FocusCommand::ShowCodeActions,
),
data: None,
},
Target::Widget(*data.main_split.tab_id),
))
}
}
}
}
_ => {}
}
}
fn lifecycle(
@ -436,6 +470,26 @@ fn paint_gutter_code_lens(
}
}
fn code_actions_rect(
&self,
text: &mut PietText,
data: &LapceEditorBufferData,
) -> Rect {
let line_height = data.config.editor.line_height as f64;
let offset = data.editor.new_cursor.offset();
let (line, _) = data.doc.buffer().offset_to_line_col(offset);
let width = 16.0;
let height = 16.0;
let char_width = data.config.editor_char_width(text);
let rect = Size::new(width, height).to_rect().with_origin(Point::new(
self.width + char_width + 3.0,
(line_height - height) / 2.0 + line_height * line as f64
- data.editor.scroll_offset.y,
));
rect
}
fn paint_code_actions_hint(
&self,
data: &LapceEditorBufferData,
@ -443,19 +497,8 @@ fn paint_code_actions_hint(
) {
if let Some(actions) = data.current_code_actions() {
if !actions.is_empty() {
let line_height = data.config.editor.line_height as f64;
let offset = data.editor.new_cursor.offset();
let (line, _) = data.doc.buffer().offset_to_line_col(offset);
let svg = get_svg("lightbulb.svg").unwrap();
let width = 16.0;
let height = 16.0;
let char_width = data.config.editor_char_width(ctx.text());
let rect =
Size::new(width, height).to_rect().with_origin(Point::new(
self.width + char_width + 3.0,
(line_height - height) / 2.0 + line_height * line as f64
- data.editor.scroll_offset.y,
));
let rect = self.code_actions_rect(ctx.text(), data);
ctx.draw_svg(
&svg,
rect,