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()),
|
lv.selected().and_then(|(i, _)| i.message_or_name()),
|
||||||
)?,
|
)?,
|
||||||
}),
|
}),
|
||||||
InputTarget::This => lv
|
InputTarget::This => {
|
||||||
|
if lv
|
||||||
.selected()
|
.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!(),
|
InputTarget::Surround => todo!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -102,7 +102,7 @@ impl LogViewer {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// TODO: inline depth
|
// 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 {
|
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);
|
let full_file_path = canonical_rustc_root.join(&file);
|
||||||
Hyperlink::new(
|
Hyperlink::new(
|
||||||
Line::from(format!("In file: {}", file.display()))
|
Line::from(format!("In file: {}:{line}", file.display()))
|
||||||
.style(styles.default),
|
.style(styles.default),
|
||||||
format!("file://{}:{line}", full_file_path.display()),
|
format!("file://{}", full_file_path.display()),
|
||||||
)
|
)
|
||||||
.render(first_line, buf);
|
.render(first_line, buf);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -115,9 +115,14 @@ impl LogEntry {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn can_be_inlined(&self, filters: &Filters) -> bool {
|
||||||
|
self.can_enter(filters)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn is_inlined(&self, filters: &Filters) -> bool {
|
pub fn is_inlined(&self, filters: &Filters) -> bool {
|
||||||
for f in filters.get() {
|
for f in filters.get() {
|
||||||
if let FilterKind::Inline = f.kind
|
if let FilterKind::Inline = f.kind
|
||||||
|
&& self.can_be_inlined(filters)
|
||||||
&& f.matcher.matches(self)
|
&& f.matcher.matches(self)
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -177,7 +182,7 @@ impl LogEntry {
|
||||||
.all_children_cache
|
.all_children_cache
|
||||||
.lock()
|
.lock()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.get(&id(&first_child))
|
.get(&id(first_child))
|
||||||
.copied()
|
.copied()
|
||||||
};
|
};
|
||||||
if let Some(cached) = cached {
|
if let Some(cached) = cached {
|
||||||
|
|
@ -194,7 +199,7 @@ impl LogEntry {
|
||||||
.all_children_cache
|
.all_children_cache
|
||||||
.lock()
|
.lock()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.insert(id(&first_child), count);
|
.insert(id(first_child), count);
|
||||||
|
|
||||||
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 {
|
pub fn line_text(&self, tree: String, filters: &Filters) -> LineText {
|
||||||
const NO_MESSAGE: &str = "<no message>";
|
const NO_MESSAGE: &str = "<no message>";
|
||||||
const SPACES_BEFORE: &str = " ";
|
const SPACES_BEFORE: &str = " ";
|
||||||
|
|
@ -281,14 +296,12 @@ impl LogEntry {
|
||||||
self.message_or_name(),
|
self.message_or_name(),
|
||||||
tree,
|
tree,
|
||||||
),
|
),
|
||||||
LogEntry::Sub {
|
LogEntry::Sub { enter, .. } => {
|
||||||
enter, children, ..
|
|
||||||
} => {
|
|
||||||
if let Some(val) = enter.all_fields().fields.get("name") {
|
if let Some(val) = enter.all_fields().fields.get("name") {
|
||||||
let (prefix, sym) = if children.first_child.is_none()
|
let (prefix, sym) = if self.has_only_return() {
|
||||||
|| children.first_child.as_ref().is_some_and(|i| i.is_return())
|
|
||||||
{
|
|
||||||
(SPACES_BEFORE.to_string(), "⟲")
|
(SPACES_BEFORE.to_string(), "⟲")
|
||||||
|
} else if !self.can_enter(filters) {
|
||||||
|
(SPACES_BEFORE.to_string(), "")
|
||||||
} else {
|
} else {
|
||||||
(
|
(
|
||||||
format!(
|
format!(
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use std::mem;
|
use std::{iter, mem};
|
||||||
|
|
||||||
use dumpster::sync::Gc;
|
use dumpster::sync::Gc;
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
|
|
@ -62,14 +62,13 @@ impl Cursor {
|
||||||
let old = self.clone();
|
let old = self.clone();
|
||||||
|
|
||||||
// if the current one is inlined
|
// if the current one is inlined
|
||||||
if self.curr_is_inlined(filters) {
|
while self.curr_is_inlined(filters) {
|
||||||
// try going one back
|
self.enter_start_internal(filters);
|
||||||
self.prev(filters);
|
self.curr.continue_in_parent = true;
|
||||||
self.next(filters);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// if the current one is removed...
|
// 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
|
// try going forwards to the next visible node
|
||||||
if self.next(filters) {
|
if self.next(filters) {
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -98,6 +97,15 @@ impl Cursor {
|
||||||
self.curr.entry.clone()
|
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>> {
|
pub fn parent(&self) -> Option<Gc<LogEntry>> {
|
||||||
self.parents.last().map(|i| i.entry.clone())
|
self.parents.last().map(|i| i.entry.clone())
|
||||||
}
|
}
|
||||||
|
|
@ -118,7 +126,11 @@ impl Cursor {
|
||||||
true
|
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 {
|
let Some(new) = self.curr().first_child() else {
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
@ -132,7 +144,11 @@ impl Cursor {
|
||||||
true
|
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 {
|
let Some(new) = self.curr().last_child() else {
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
@ -223,7 +239,7 @@ impl Cursor {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.enter_end_internal();
|
self.enter_end_internal(filters);
|
||||||
self.curr.continue_in_parent = true;
|
self.curr.continue_in_parent = true;
|
||||||
self.update(filters)
|
self.update(filters)
|
||||||
}
|
}
|
||||||
|
|
@ -237,14 +253,14 @@ impl Cursor {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.enter_start_internal();
|
self.enter_start_internal(filters);
|
||||||
self.curr.continue_in_parent = true;
|
self.curr.continue_in_parent = true;
|
||||||
self.update(filters)
|
self.update(filters)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn enter(&mut self, filters: &Filters) -> bool {
|
pub fn enter(&mut self, filters: &Filters) -> bool {
|
||||||
let before = self.clone();
|
let before = self.clone();
|
||||||
if !self.enter_start_internal() {
|
if !self.enter_start_internal(filters) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -107,6 +107,7 @@ impl LogFileEntryGenerator {
|
||||||
|
|
||||||
struct Inner {
|
struct Inner {
|
||||||
pub path: PathBuf,
|
pub path: PathBuf,
|
||||||
|
#[allow(unused)]
|
||||||
pub jh: Option<JoinHandle<()>>,
|
pub jh: Option<JoinHandle<()>>,
|
||||||
first: Option<Gc<LogEntry>>,
|
first: Option<Gc<LogEntry>>,
|
||||||
}
|
}
|
||||||
|
|
@ -435,4 +436,42 @@ mod tests {
|
||||||
assert_eq!(c.curr().message_or_name(), Some("foo".to_string()));
|
assert_eq!(c.curr().message_or_name(), Some("foo".to_string()));
|
||||||
assert!(!c.prev(&f));
|
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 dumpster::sync::Gc;
|
||||||
use itertools::Itertools;
|
|
||||||
use ratatui::widgets::{List, ListItem, Widget};
|
use ratatui::widgets::{List, ListItem, Widget};
|
||||||
use regex::Regex;
|
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> {
|
pub struct Items<'a> {
|
||||||
items: Vec<(Gc<LogEntry>, usize)>,
|
items: Vec<(Gc<LogEntry>, usize)>,
|
||||||
selected_offset: usize,
|
selected_offset: usize,
|
||||||
|
|
@ -132,18 +59,25 @@ impl Widget for Styled<'_, &Items<'_>> {
|
||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
{
|
{
|
||||||
let ts = TreeState::from_items(&self.items);
|
|
||||||
let regex_cache = OnceCell::new();
|
let regex_cache = OnceCell::new();
|
||||||
|
|
||||||
let list = List::new(
|
let list = List::new(
|
||||||
self.inner
|
self.inner
|
||||||
.items
|
.items
|
||||||
.iter()
|
.iter()
|
||||||
.map(|(entry, _)| entry)
|
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.zip(ts.tree_prefixes)
|
.map(|(idx, (entry, depth))| {
|
||||||
.map(|((idx, entry), tree)| {
|
let prefix = if *depth == 0 {
|
||||||
let line_text = entry.line_text(tree, self.filters);
|
"".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);
|
let mut line = line_text.styled(&self.styles);
|
||||||
if idx == self.selected_offset
|
if idx == self.selected_offset
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue