fix some (but far from all) visual bugs
This commit is contained in:
parent
d0bc7e952c
commit
b668a894c7
7 changed files with 114 additions and 104 deletions
|
|
@ -90,9 +90,17 @@ impl Matcher {
|
|||
lv.selected().and_then(|(i, _)| i.message_or_name()),
|
||||
)?,
|
||||
}),
|
||||
InputTarget::This => lv
|
||||
InputTarget::This => {
|
||||
if lv
|
||||
.selected()
|
||||
.map(|(i, _)| Self::Specific { hash: i.hash() }),
|
||||
.is_none_or(|(i, _)| !i.can_be_inlined(&lv.filters))
|
||||
{
|
||||
return None;
|
||||
}
|
||||
|
||||
lv.selected()
|
||||
.map(|(i, _)| Self::Specific { hash: i.hash() })
|
||||
}
|
||||
InputTarget::Surround => todo!(),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -102,7 +102,7 @@ impl LogViewer {
|
|||
break;
|
||||
}
|
||||
// TODO: inline depth
|
||||
res.push((temp_iter.curr(), 0));
|
||||
res.push((temp_iter.curr(), temp_iter.inline_depth()));
|
||||
}
|
||||
|
||||
if !res.is_empty() && self.view.selection_offset > res.len() - 1 {
|
||||
|
|
|
|||
|
|
@ -641,9 +641,9 @@ impl Widget for &mut App {
|
|||
{
|
||||
let full_file_path = canonical_rustc_root.join(&file);
|
||||
Hyperlink::new(
|
||||
Line::from(format!("In file: {}", file.display()))
|
||||
Line::from(format!("In file: {}:{line}", file.display()))
|
||||
.style(styles.default),
|
||||
format!("file://{}:{line}", full_file_path.display()),
|
||||
format!("file://{}", full_file_path.display()),
|
||||
)
|
||||
.render(first_line, buf);
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -115,9 +115,14 @@ impl LogEntry {
|
|||
false
|
||||
}
|
||||
|
||||
pub fn can_be_inlined(&self, filters: &Filters) -> bool {
|
||||
self.can_enter(filters)
|
||||
}
|
||||
|
||||
pub fn is_inlined(&self, filters: &Filters) -> bool {
|
||||
for f in filters.get() {
|
||||
if let FilterKind::Inline = f.kind
|
||||
&& self.can_be_inlined(filters)
|
||||
&& f.matcher.matches(self)
|
||||
{
|
||||
return true;
|
||||
|
|
@ -177,7 +182,7 @@ impl LogEntry {
|
|||
.all_children_cache
|
||||
.lock()
|
||||
.unwrap()
|
||||
.get(&id(&first_child))
|
||||
.get(&id(first_child))
|
||||
.copied()
|
||||
};
|
||||
if let Some(cached) = cached {
|
||||
|
|
@ -194,7 +199,7 @@ impl LogEntry {
|
|||
.all_children_cache
|
||||
.lock()
|
||||
.unwrap()
|
||||
.insert(id(&first_child), count);
|
||||
.insert(id(first_child), count);
|
||||
|
||||
count
|
||||
}
|
||||
|
|
@ -255,6 +260,16 @@ impl LogEntry {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn has_only_return(&self) -> bool {
|
||||
matches!(self, Self::Sub { children, .. } if children.first_child.as_ref().is_some_and(|i| i.is_return()))
|
||||
}
|
||||
|
||||
pub fn can_enter(&self, filters: &Filters) -> bool {
|
||||
matches!(self, Self::Sub { children, .. } if children.first_child.is_some())
|
||||
&& !self.has_only_return()
|
||||
&& self.all_children(filters) != 0
|
||||
}
|
||||
|
||||
pub fn line_text(&self, tree: String, filters: &Filters) -> LineText {
|
||||
const NO_MESSAGE: &str = "<no message>";
|
||||
const SPACES_BEFORE: &str = " ";
|
||||
|
|
@ -281,14 +296,12 @@ impl LogEntry {
|
|||
self.message_or_name(),
|
||||
tree,
|
||||
),
|
||||
LogEntry::Sub {
|
||||
enter, children, ..
|
||||
} => {
|
||||
LogEntry::Sub { enter, .. } => {
|
||||
if let Some(val) = enter.all_fields().fields.get("name") {
|
||||
let (prefix, sym) = if children.first_child.is_none()
|
||||
|| children.first_child.as_ref().is_some_and(|i| i.is_return())
|
||||
{
|
||||
let (prefix, sym) = if self.has_only_return() {
|
||||
(SPACES_BEFORE.to_string(), "⟲")
|
||||
} else if !self.can_enter(filters) {
|
||||
(SPACES_BEFORE.to_string(), "")
|
||||
} else {
|
||||
(
|
||||
format!(
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use std::mem;
|
||||
use std::{iter, mem};
|
||||
|
||||
use dumpster::sync::Gc;
|
||||
use itertools::Itertools;
|
||||
|
|
@ -62,14 +62,13 @@ impl Cursor {
|
|||
let old = self.clone();
|
||||
|
||||
// if the current one is inlined
|
||||
if self.curr_is_inlined(filters) {
|
||||
// try going one back
|
||||
self.prev(filters);
|
||||
self.next(filters);
|
||||
while self.curr_is_inlined(filters) {
|
||||
self.enter_start_internal(filters);
|
||||
self.curr.continue_in_parent = true;
|
||||
}
|
||||
|
||||
// if the current one is removed...
|
||||
if self.curr_is_removed(filters) || self.curr_is_inlined(filters) {
|
||||
if self.curr_is_removed(filters) {
|
||||
// try going forwards to the next visible node
|
||||
if self.next(filters) {
|
||||
return true;
|
||||
|
|
@ -98,6 +97,15 @@ impl Cursor {
|
|||
self.curr.entry.clone()
|
||||
}
|
||||
|
||||
pub fn inline_depth(&self) -> usize {
|
||||
self.parents
|
||||
.iter()
|
||||
.chain(iter::once(&self.curr))
|
||||
.rev()
|
||||
.take_while(|i| i.continue_in_parent)
|
||||
.count()
|
||||
}
|
||||
|
||||
pub fn parent(&self) -> Option<Gc<LogEntry>> {
|
||||
self.parents.last().map(|i| i.entry.clone())
|
||||
}
|
||||
|
|
@ -118,7 +126,11 @@ impl Cursor {
|
|||
true
|
||||
}
|
||||
|
||||
fn enter_start_internal(&mut self) -> bool {
|
||||
fn enter_start_internal(&mut self, filters: &Filters) -> bool {
|
||||
if !self.curr().can_enter(filters) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let Some(new) = self.curr().first_child() else {
|
||||
return false;
|
||||
};
|
||||
|
|
@ -132,7 +144,11 @@ impl Cursor {
|
|||
true
|
||||
}
|
||||
|
||||
fn enter_end_internal(&mut self) -> bool {
|
||||
fn enter_end_internal(&mut self, filters: &Filters) -> bool {
|
||||
if !self.curr().can_enter(filters) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let Some(new) = self.curr().last_child() else {
|
||||
return false;
|
||||
};
|
||||
|
|
@ -223,7 +239,7 @@ impl Cursor {
|
|||
return true;
|
||||
}
|
||||
|
||||
self.enter_end_internal();
|
||||
self.enter_end_internal(filters);
|
||||
self.curr.continue_in_parent = true;
|
||||
self.update(filters)
|
||||
}
|
||||
|
|
@ -237,14 +253,14 @@ impl Cursor {
|
|||
return true;
|
||||
}
|
||||
|
||||
self.enter_start_internal();
|
||||
self.enter_start_internal(filters);
|
||||
self.curr.continue_in_parent = true;
|
||||
self.update(filters)
|
||||
}
|
||||
|
||||
pub fn enter(&mut self, filters: &Filters) -> bool {
|
||||
let before = self.clone();
|
||||
if !self.enter_start_internal() {
|
||||
if !self.enter_start_internal(filters) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -107,6 +107,7 @@ impl LogFileEntryGenerator {
|
|||
|
||||
struct Inner {
|
||||
pub path: PathBuf,
|
||||
#[allow(unused)]
|
||||
pub jh: Option<JoinHandle<()>>,
|
||||
first: Option<Gc<LogEntry>>,
|
||||
}
|
||||
|
|
@ -435,4 +436,42 @@ mod tests {
|
|||
assert_eq!(c.curr().message_or_name(), Some("foo".to_string()));
|
||||
assert!(!c.prev(&f));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn inline_depth() {
|
||||
let mut c = parse(
|
||||
&[
|
||||
with_fields(r#"{"message": "enter", "name": "nest1"}"#),
|
||||
with_fields(r#"{"message": "enter", "name": "nest2"}"#),
|
||||
with_fields(r#"{"message": "baz"}"#),
|
||||
with_fields(r#"{"message": "exit"}"#),
|
||||
with_fields(r#"{"message": "exit"}"#),
|
||||
]
|
||||
.join("\n"),
|
||||
);
|
||||
let mut f = filters();
|
||||
c.enter(&f);
|
||||
c.enter(&f);
|
||||
assert_eq!(c.curr().message_or_name(), Some("baz".to_string()));
|
||||
c.exit(&f);
|
||||
c.exit(&f);
|
||||
|
||||
f.push(Arc::new(Filter {
|
||||
matcher: Matcher::Field {
|
||||
name: "name".to_string(),
|
||||
value: MatcherValue::Exact("nest1".to_string()),
|
||||
},
|
||||
kind: FilterKind::Inline,
|
||||
}));
|
||||
f.push(Arc::new(Filter {
|
||||
matcher: Matcher::Field {
|
||||
name: "name".to_string(),
|
||||
value: MatcherValue::Exact("nest2".to_string()),
|
||||
},
|
||||
kind: FilterKind::Inline,
|
||||
}));
|
||||
c.update_with_parents(&f);
|
||||
|
||||
assert_eq!(c.curr().message_or_name(), Some("baz".to_string()));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
use std::{cell::OnceCell, iter};
|
||||
use std::cell::OnceCell;
|
||||
|
||||
use dumpster::sync::Gc;
|
||||
use itertools::Itertools;
|
||||
use ratatui::widgets::{List, ListItem, Widget};
|
||||
use regex::Regex;
|
||||
|
||||
|
|
@ -18,78 +17,6 @@ use crate::tui::{
|
|||
},
|
||||
};
|
||||
|
||||
pub struct TreeState {
|
||||
tree_prefixes: Vec<String>,
|
||||
}
|
||||
|
||||
impl TreeState {
|
||||
pub fn from_items(items: &[(Gc<LogEntry>, usize)]) -> Self {
|
||||
let mut res = Vec::new();
|
||||
let mut curr = String::new();
|
||||
let mut prev_depth = 0;
|
||||
|
||||
for (depth, next_depth) in items
|
||||
.iter()
|
||||
.map(|i| i.1 as isize)
|
||||
.chain(iter::once(-1isize))
|
||||
.tuple_windows()
|
||||
{
|
||||
if depth > prev_depth {
|
||||
if depth > 1 {
|
||||
let _ = curr.pop();
|
||||
let _ = curr.pop();
|
||||
curr.push('│');
|
||||
curr.push(' ');
|
||||
}
|
||||
for _ in prev_depth..depth.saturating_sub(2) {
|
||||
curr.push(' ');
|
||||
curr.push(' ');
|
||||
}
|
||||
if next_depth < depth {
|
||||
curr.push('└');
|
||||
curr.push('─');
|
||||
} else {
|
||||
curr.push('├');
|
||||
curr.push('─');
|
||||
}
|
||||
} else if depth == prev_depth && next_depth < prev_depth {
|
||||
let _ = curr.pop();
|
||||
let _ = curr.pop();
|
||||
curr.push('└');
|
||||
curr.push('─');
|
||||
} else if depth < prev_depth {
|
||||
for _ in depth..prev_depth {
|
||||
let _ = curr.pop();
|
||||
let _ = curr.pop();
|
||||
let _ = curr.pop();
|
||||
let _ = curr.pop();
|
||||
}
|
||||
|
||||
if depth > 0 {
|
||||
let _ = curr.pop();
|
||||
let _ = curr.pop();
|
||||
if next_depth < depth {
|
||||
curr.push('└');
|
||||
curr.push('─');
|
||||
} else {
|
||||
curr.push('├');
|
||||
curr.push('─');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
prev_depth = depth;
|
||||
if depth != 0 {
|
||||
res.push(format!("{curr} "));
|
||||
} else {
|
||||
res.push(String::new());
|
||||
}
|
||||
}
|
||||
|
||||
Self { tree_prefixes: res }
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Items<'a> {
|
||||
items: Vec<(Gc<LogEntry>, usize)>,
|
||||
selected_offset: usize,
|
||||
|
|
@ -132,18 +59,25 @@ impl Widget for Styled<'_, &Items<'_>> {
|
|||
where
|
||||
Self: Sized,
|
||||
{
|
||||
let ts = TreeState::from_items(&self.items);
|
||||
let regex_cache = OnceCell::new();
|
||||
|
||||
let list = List::new(
|
||||
self.inner
|
||||
.items
|
||||
.iter()
|
||||
.map(|(entry, _)| entry)
|
||||
.enumerate()
|
||||
.zip(ts.tree_prefixes)
|
||||
.map(|((idx, entry), tree)| {
|
||||
let line_text = entry.line_text(tree, self.filters);
|
||||
.map(|(idx, (entry, depth))| {
|
||||
let prefix = if *depth == 0 {
|
||||
"".to_string()
|
||||
} else {
|
||||
let mut res = String::new();
|
||||
for _ in 0..*depth - 1 {
|
||||
res.push_str(" ");
|
||||
}
|
||||
res.push_str("- ");
|
||||
res
|
||||
};
|
||||
let line_text = entry.line_text(prefix, self.filters);
|
||||
|
||||
let mut line = line_text.styled(&self.styles);
|
||||
if idx == self.selected_offset
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue