Skip to content

Commit

Permalink
feat: basic support for declaration jump (close #11)
Browse files Browse the repository at this point in the history
potential improvements:
* expand before jump: currently only search for ids in treelines instead
  of DModule tree, because the expansion and jump interaction is vague.
  For simplicity, expand all, search and jump.
* use defining ids in treelines: replace reexport ids by inner id in DModule
* width & wrapping: this needs to add a new_with_width API on
  declarationLines
  • Loading branch information
zjp-CN committed Mar 23, 2024
1 parent 1fe8633 commit 6559ede
Show file tree
Hide file tree
Showing 5 changed files with 106 additions and 1 deletion.
47 changes: 46 additions & 1 deletion src/bin/page/content.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,12 @@ use ratatui::{
prelude::*,
widgets::{Block, BorderType, Borders},
};
use std::ops::Range;
use term_rustdoc::{
tree::{CrateDoc, IDMap},
tree::{CrateDoc, IDMap, ID},
type_name::{DeclarationLine, DeclarationLines},
};
use unicode_width::UnicodeWidthStr;

#[derive(Default)]
pub(super) struct ContentInner {
Expand Down Expand Up @@ -76,6 +78,10 @@ impl ContentInner {
pub fn reset_doc(&mut self) {
self.md.lines.reset_doc();
}

pub fn jumpable_id(&self, x: u16, y: u16) -> Option<ID> {
self.decl.display.jumpable_id(x, y)
}
}

struct Declaration {
Expand All @@ -101,6 +107,14 @@ impl Default for Declaration {
#[derive(Default)]
struct DeclarationInner {
inner: Scroll<DeclarationLines>,
jumpable_ids: Vec<JumpableId>,
}

#[derive(Debug)]
struct JumpableId {
y: u16,
x: Range<u16>,
id: ID,
}

impl DeclarationInner {
Expand All @@ -127,8 +141,38 @@ impl DeclarationInner {
}

fn update_decl(&mut self, lines: DeclarationLines) {
// self.jumpable_ids = lines.it;
let mut jumpable_ids = Vec::new();
let mut col = 0;
for (y, line) in lines.iter().enumerate() {
for tt in &**line {
let width = tt.text.width();
if let Some(id) = &tt.id {
let end = col + width;
jumpable_ids.push(JumpableId {
y: y as u16,
x: col as u16..end as u16,
id: id.clone(),
});
}
col += width;
}
col = 0;
}
info!(?jumpable_ids);
self.jumpable_ids = jumpable_ids;
self.inner.lines = lines;
}

fn jumpable_id(&self, x: u16, y: u16) -> Option<ID> {
let area = self.inner.area;
let x = x.checked_sub(area.x)?;
let y = y.checked_sub(area.y)?;
info!(y, x);
self.jumpable_ids
.iter()
.find_map(|jump| (jump.y == y && jump.x.contains(&x)).then(|| jump.id.clone()))
}
}

/// No need to query state for previous line.
Expand All @@ -145,6 +189,7 @@ impl Declaration {
let lines = DeclarationLines::new(id, map);
if lines.is_empty() {
self.display.scroll_text().lines = Default::default();
self.display.jumpable_ids = Vec::new();
} else {
self.display.update_decl(lines);
// self.display.rust_code(&code, width);
Expand Down
4 changes: 4 additions & 0 deletions src/bin/page/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -162,4 +162,8 @@ impl Content {
fn update_doc(&mut self, id: &str) -> Option<crate::ui::scrollable::Headings> {
self.inner.update_doc(id, self.border.inner())
}

fn jumpable_id(&self, x: u16, y: u16) -> Option<ID> {
self.inner.jumpable_id(x, y)
}
}
32 changes: 32 additions & 0 deletions src/bin/page/page_scroll.rs
Original file line number Diff line number Diff line change
Expand Up @@ -172,4 +172,36 @@ impl Page {
self.content().lines.toggle_sytect();
self.update_content();
}

pub fn jump_to_id(&mut self, id: &str) {
let outline = self.outline.display_ref();
let map = outline.lines.doc_ref();
if let Some(current) = outline.get_line_of_current_cursor() {
if let Some(current_id) = &current.id {
if map.is_same_id(current_id, id) {
info!(?current_id, ?id, path = %map.path(id), "no need to jump to");
return;
}
}
}
let iter = &mut outline.lines.iter();
if let Some(pos) = iter.position(|l| {
l.id.as_deref()
// .map(|src| src == id)
.map(|src| map.is_same_id(src, id))
.unwrap_or(false)
}) {
let start = pos.saturating_sub(6);
let y = (pos - start) as u16;
self.outline().start = start;
self.outline().set_cursor(y);
self.update_content();
info!(
"succeed to jump to {:?}",
self.outline().lines.doc_ref().path(id)
);
} else {
error!(?id, path = %map.path(id), "unable to jump to");
}
}
}
3 changes: 3 additions & 0 deletions src/bin/page/panel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ impl super::Page {
self.update_content();
set!(outline)
} else if self.content.border.area().contains(position) {
if let Some(id) = self.content.jumpable_id(x, y) {
self.jump_to_id(&id);
}
set!(content)
} else if self.navi.contains(position) {
if self.heading_jump(y) {
Expand Down
21 changes: 21 additions & 0 deletions src/tree/id.rs
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,27 @@ impl IDMap {
id.into()
}
}

/// Since there will be reexported item id, we have to check the real defining id.
pub fn is_same_id(&self, src: &str, target: &str) -> bool {
if src == target {
info!("found exactly same id {src}");
return true;
}
self.get_item(src)
.map(|item| match &item.inner {
// FIXME: check id for primitive types
ItemEnum::Import(x) => {
let res = x.id.as_ref().map(|id| id.0 == target).unwrap_or(false);
if res {
info!(src, target, "found same id through reexport item");
}
res
}
_ => false,
})
.unwrap_or(false)
}
}

/// Deduce the name from its item type.
Expand Down

0 comments on commit 6559ede

Please sign in to comment.