Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

show call hierarchy and jump to location #114

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions lapce-app/src/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -746,6 +746,9 @@ pub enum InternalCommand {
tab_index: usize,
terminal_index: usize,
},
CallHierarchyIncoming {
item_id: ViewId,
},
}

#[derive(Clone)]
Expand Down
49 changes: 32 additions & 17 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,41 @@ 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_id: item.get_untracked().view_id,
},
);
}
}
},
}),
);
}

Expand Down Expand Up @@ -2625,9 +2640,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
242 changes: 242 additions & 0 deletions lapce-app/src/panel/call_hierarchy_view.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,242 @@
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
}

pub fn find_by_id(
root: RwSignal<CallHierarchyItemData>,
view_id: ViewId,
) -> Option<RwSignal<CallHierarchyItemData>> {
if root.get_untracked().view_id == view_id {
Some(root)
} else {
root.get_untracked()
.children
.get_untracked()
.into_iter()
.find_map(|x| Self::find_by_id(x, view_id))
}
}
}

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_id: rw_data.get_untracked().view_id,
},
);
}
}
}),
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_id: rw_data.get_untracked().view_id },
);
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
Loading