Skip to content

Commit

Permalink
show call hierarchy and jump to location
Browse files Browse the repository at this point in the history
  • Loading branch information
jm-observer committed Aug 5, 2024
1 parent 0f1aedd commit b2a74f4
Show file tree
Hide file tree
Showing 9 changed files with 351 additions and 24 deletions.
5 changes: 5 additions & 0 deletions lapce-app/src/command.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use std::{path::PathBuf, rc::Rc, sync::Arc};

use floem::reactive::RwSignal;
pub use floem::views::editor::command::CommandExecuted;
use floem::{
keyboard::Modifiers, peniko::kurbo::Vec2, views::editor::command::Command,
Expand All @@ -21,6 +22,7 @@ use serde_json::Value;
use strum::{EnumMessage, IntoEnumIterator};
use strum_macros::{Display, EnumIter, EnumMessage, EnumString, IntoStaticStr};

use crate::panel::call_hierarchy_view::CallHierarchyItemData;
use crate::{
alert::AlertButton,
debug::RunDebugMode,
Expand Down Expand Up @@ -746,6 +748,9 @@ pub enum InternalCommand {
tab_index: usize,
terminal_index: usize,
},
CallHierarchyIncoming {
item: RwSignal<CallHierarchyItemData>,
},
}

#[derive(Clone)]
Expand Down
50 changes: 32 additions & 18 deletions lapce-app/src/editor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ use floem::{
visual_line::{ConfigId, Lines, TextLayoutProvider, VLine, VLineInfo},
Editor,
},
ViewId,
};
use itertools::Itertools;
use lapce_core::{
Expand All @@ -48,7 +49,7 @@ use lapce_xi_rope::{Rope, RopeDelta, Transformer};
use lsp_types::{
CompletionItem, CompletionTextEdit, GotoDefinitionResponse, HoverContents,
InlayHint, InlayHintLabel, InlineCompletionTriggerKind, Location, MarkedString,
MarkupKind, TextEdit,
MarkupKind, Range, TextEdit,
};
use serde::{Deserialize, Serialize};

Expand All @@ -71,6 +72,7 @@ use crate::{
markdown::{
from_marked_string, from_plaintext, parse_markdown, MarkdownContent,
},
panel::{call_hierarchy_view::CallHierarchyItemData, kind::PanelKind},
snippet::Snippet,
tracing::*,
window_tab::{CommonData, Focus, WindowTabData},
Expand Down Expand Up @@ -1267,7 +1269,7 @@ impl EditorData {
);
}

pub fn show_call_hierarchy(&self) {
pub fn call_hierarchy(&self, window_tab_data: WindowTabData) {
let doc = self.doc();
let path = match if doc.loaded() {
doc.content.with_untracked(|c| c.path().cloned())
Expand All @@ -1285,28 +1287,40 @@ impl EditorData {
let position = buffer.offset_to_position(offset);
(start_position, position)
});

let send = create_ext_action(self.scope, move |_rs| {
tracing::debug!("{:?}", _rs);
});
let proxy = self.common.proxy.clone();
let scope = window_tab_data.scope;
let range = Range {
start: _start_position,
end: position,
};
self.common.proxy.show_call_hierarchy(
path.clone(),
path,
position,
move |result| {
create_ext_action(self.scope, move |result| {
if let Ok(ProxyResponse::ShowCallHierarchyResponse {
items, ..
}) = result
{
if let Some(item) = items.and_then(|x| x.into_iter().next()) {
proxy.call_hierarchy_incoming(
path.clone(),
item.clone(),
send,
);
let root = scope.create_rw_signal(CallHierarchyItemData {
view_id: ViewId::new(),
item: Rc::new(item),
from_range: range,
init: false,
open: scope.create_rw_signal(true),
children: scope.create_rw_signal(Vec::with_capacity(0)),
});
let item = root;
window_tab_data.call_hierarchy_data.root.update(|x| {
*x = Some(root);
});
window_tab_data.show_panel(PanelKind::CallHierarchy);
window_tab_data
.common
.internal_command
.send(InternalCommand::CallHierarchyIncoming { item });
}
}
},
}),
);
}

Expand Down Expand Up @@ -2625,9 +2639,9 @@ impl EditorData {
vec![
Some(CommandKind::Focus(FocusCommand::GotoDefinition)),
Some(CommandKind::Focus(FocusCommand::GotoTypeDefinition)),
// Some(CommandKind::Workbench(
// LapceWorkbenchCommand::ShowCallHierarchy,
// )),
Some(CommandKind::Workbench(
LapceWorkbenchCommand::ShowCallHierarchy,
)),
None,
Some(CommandKind::Focus(FocusCommand::Rename)),
None,
Expand Down
2 changes: 1 addition & 1 deletion lapce-app/src/main_split.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2164,7 +2164,7 @@ impl MainSplitData {
}
}

pub fn run_code_lens(&self, args: &Vec<Value>, command: &str) {
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) {
Expand Down
227 changes: 227 additions & 0 deletions lapce-app/src/panel/call_hierarchy_view.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,227 @@
use std::{ops::AddAssign, rc::Rc};

use floem::{
event::EventPropagation,
reactive::RwSignal,
style::{AlignItems, CursorStyle},
views::{
container, label, scroll, stack, svg, virtual_stack, Decorators,
VirtualDirection, VirtualItemSize, VirtualVector,
},
View, ViewId,
};
use lsp_types::{CallHierarchyItem, Range};

use super::position::PanelPosition;
use crate::{
command::InternalCommand,
config::{color::LapceColor, icon::LapceIcons},
editor::location::EditorLocation,
window_tab::CommonData,
window_tab::WindowTabData,
};

#[derive(Clone, Debug)]
pub struct CallHierarchyData {
pub root: RwSignal<Option<RwSignal<CallHierarchyItemData>>>,
pub common: Rc<CommonData>,
pub scroll_to_line: RwSignal<Option<f64>>,
}

#[derive(Debug, Clone)]
pub struct CallHierarchyItemData {
pub view_id: ViewId,
pub item: Rc<CallHierarchyItem>,
pub from_range: Range,
pub init: bool,
pub open: RwSignal<bool>,
pub children: RwSignal<Vec<RwSignal<CallHierarchyItemData>>>,
}

impl CallHierarchyItemData {
pub fn child_count(&self) -> usize {
let mut count = 1;
if self.open.get() {
for child in self.children.get_untracked() {
count += child.with(|x| x.child_count())
}
}
count
}
}

fn get_children(
data: RwSignal<CallHierarchyItemData>,
next: &mut usize,
min: usize,
max: usize,
level: usize,
) -> Vec<(usize, usize, RwSignal<CallHierarchyItemData>)> {
let mut children = Vec::new();
if *next >= min && *next < max {
children.push((*next, level, data));
} else if *next >= max {
return children;
}
next.add_assign(1);
if data.get_untracked().open.get() {
for child in data.get().children.get_untracked() {
let child_children = get_children(child, next, min, max, level + 1);
children.extend(child_children);
if *next > max {
break;
}
}
}
children
}

pub struct VirtualList {
root: Option<RwSignal<CallHierarchyItemData>>,
}

impl VirtualList {
pub fn new(root: Option<RwSignal<CallHierarchyItemData>>) -> Self {
Self { root }
}
}

impl VirtualVector<(usize, usize, RwSignal<CallHierarchyItemData>)> for VirtualList {
fn total_len(&self) -> usize {
if let Some(root) = &self.root {
root.with(|x| x.child_count())
} else {
0
}
}

fn slice(
&mut self,
range: std::ops::Range<usize>,
) -> impl Iterator<Item = (usize, usize, RwSignal<CallHierarchyItemData>)> {
if let Some(root) = &self.root {
let min = range.start;
let max = range.end;
let children = get_children(*root, &mut 0, min, max, 0);
children.into_iter()
} else {
Vec::new().into_iter()
}
}
}
pub fn show_hierarchy_panel(
window_tab_data: Rc<WindowTabData>,
_position: PanelPosition,
) -> impl View {
let call_hierarchy_data = window_tab_data.call_hierarchy_data.clone();
let config = call_hierarchy_data.common.config;
let ui_line_height = call_hierarchy_data.common.ui_line_height;
let scroll_to_line = call_hierarchy_data.scroll_to_line;
scroll(
virtual_stack(
VirtualDirection::Vertical,
VirtualItemSize::Fixed(Box::new(move || ui_line_height.get())),
move || VirtualList::new(call_hierarchy_data.root.get()),
move |(_, _, item)| item.get_untracked().view_id,
move |(_, level, rw_data)| {
let data = rw_data.get_untracked();
let open = data.open;
stack((
svg(move || {
let config = config.get();
let svg_str = match open.get() {
true => LapceIcons::ITEM_OPENED,
false => LapceIcons::ITEM_CLOSED,
};
config.ui_svg(svg_str)
})
.style(move |s| {
let config = config.get();
let size = config.ui.icon_size() as f32;
s.size(size, size)
.flex_shrink(0.0)
.margin_left(10.0)
.margin_right(6.0)
.color(config.color(LapceColor::LAPCE_ICON_ACTIVE))
}).on_click_stop({
let window_tab_data = window_tab_data.clone();
move |_x| {
open.update(|x| {
*x = !*x;
});
if !rw_data.get_untracked().init {
window_tab_data.common.internal_command.send(
InternalCommand::CallHierarchyIncoming {
item: rw_data,
},
);
}
}
}),
container(
label(move || {
format!(
"{} {} {}",
data.item.name,
data.item.detail.as_deref().unwrap_or(""), data.from_range.start.line
)
})
.style(move |s| {
s.flex_grow(1.0)
.height(ui_line_height.get())
.selectable(false)
.align_items(AlignItems::Center)
}),
)
.style(|s| s.flex_grow(1.0).padding(0.0).margin(0.0)),
))
.style(move |s| {
s.padding_right(5.0)
.padding_left((level * 10) as f32)
.align_items(AlignItems::Center)
.hover(|s| {
s.background(
config
.get()
.color(LapceColor::PANEL_HOVERED_BACKGROUND),
)
.cursor(CursorStyle::Pointer)
})
})
.on_double_click({
let window_tab_data = window_tab_data.clone();
let data = rw_data;
move |_| {
window_tab_data.common.internal_command.send(
InternalCommand::CallHierarchyIncoming { item: rw_data },
);
let data = data.get_untracked();
if let Ok(path) = data.item.uri.to_file_path() {
window_tab_data
.common
.internal_command
.send(InternalCommand::GoToLocation { location: EditorLocation {
path,
position: Some(crate::editor::location::EditorPosition::Position(data.from_range.start)),
scroll_offset: None,
ignore_unconfirmed: false,
same_editor_tab: false,
} });
}
EventPropagation::Stop
}
})
},
)
.style(|s| s.flex_col().align_items(AlignItems::Stretch).width_full()),
)
.style(|s| s.size_full())
.scroll_to(move || {
if let Some(line) = scroll_to_line.get() {
let line_height = ui_line_height.get();
Some((0.0, line * line_height).into())
} else {
None
}
})
}
7 changes: 6 additions & 1 deletion lapce-app/src/panel/data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,12 @@ pub fn default_panel_order() -> PanelOrder {
);
order.insert(
PanelPosition::BottomLeft,
im::vector![PanelKind::Terminal, PanelKind::Search, PanelKind::Problem,],
im::vector![
PanelKind::Terminal,
PanelKind::Search,
PanelKind::Problem,
PanelKind::CallHierarchy
],
);

order
Expand Down
2 changes: 2 additions & 0 deletions lapce-app/src/panel/kind.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ pub enum PanelKind {
Search,
Problem,
Debug,
CallHierarchy,
}

impl PanelKind {
Expand All @@ -27,6 +28,7 @@ impl PanelKind {
PanelKind::Search => LapceIcons::SEARCH,
PanelKind::Problem => LapceIcons::PROBLEM,
PanelKind::Debug => LapceIcons::DEBUG,
PanelKind::CallHierarchy => LapceIcons::LINK,
}
}

Expand Down
1 change: 1 addition & 0 deletions lapce-app/src/panel/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
pub mod call_hierarchy_view;
pub mod data;
pub mod debug_view;
pub mod global_search_view;
Expand Down
Loading

0 comments on commit b2a74f4

Please sign in to comment.