mirror of
https://codeberg.org/icewind/logsmash.git
synced 2026-06-03 10:04:12 +02:00
add option to copy all lines in view
This commit is contained in:
parent
dd4b6260a1
commit
668512a767
5 changed files with 57 additions and 19 deletions
19
src/main.rs
19
src/main.rs
|
|
@ -5,6 +5,8 @@ use crate::logs::ParsedLogs;
|
|||
use crate::matcher::{MatchResult, Matcher};
|
||||
use crate::ui::run_ui;
|
||||
use base64::prelude::*;
|
||||
use clap::builder::styling::{AnsiColor, Effects};
|
||||
use clap::builder::Styles;
|
||||
use clap::Parser;
|
||||
use either::Either;
|
||||
use indicatif::{ParallelProgressIterator, ProgressStyle};
|
||||
|
|
@ -20,6 +22,8 @@ use std::io::{read_to_string, stdin, BufReader, Stderr, Write};
|
|||
use std::iter::once;
|
||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||
use std::sync::RwLock;
|
||||
use std::thread::sleep;
|
||||
use std::time::Duration;
|
||||
|
||||
mod app;
|
||||
mod error;
|
||||
|
|
@ -39,8 +43,16 @@ use time::format_description::{parse_owned, parse_strftime_owned};
|
|||
#[global_allocator]
|
||||
static GLOBAL: Jemalloc = Jemalloc;
|
||||
|
||||
fn styles() -> Styles {
|
||||
Styles::styled()
|
||||
.header(AnsiColor::Yellow.on_default() | Effects::BOLD)
|
||||
.usage(AnsiColor::Yellow.on_default() | Effects::BOLD)
|
||||
.literal(AnsiColor::Blue.on_default() | Effects::BOLD)
|
||||
.placeholder(AnsiColor::Green.on_default())
|
||||
}
|
||||
|
||||
#[derive(Debug, Parser)]
|
||||
#[command(version, about, long_about = None)]
|
||||
#[command(version, about, long_about = None, styles = styles())]
|
||||
struct Args {
|
||||
/// Files to read from, or "-" for stdin
|
||||
files: Vec<String>,
|
||||
|
|
@ -199,7 +211,10 @@ fn main() -> MainResult {
|
|||
}
|
||||
|
||||
fn copy_osc(text: &str) {
|
||||
print!("\x1B]52;c;{}\x07", BASE64_STANDARD.encode(text))
|
||||
print!("\x1B]52;c;{}\x07", BASE64_STANDARD.encode(text));
|
||||
// seems to be very unreliable without doing it twice ¯\_(ツ)_/¯
|
||||
sleep(Duration::from_millis(100));
|
||||
print!("\x1B]52;c;{}\x07", BASE64_STANDARD.encode(text));
|
||||
}
|
||||
|
||||
fn parse_line(mut line: &str) -> Result<LogLine, serde_json::Error> {
|
||||
|
|
|
|||
|
|
@ -58,10 +58,10 @@ fn help(page: UiPage) -> &'static str {
|
|||
UiPage::GroupList => "«Q» Exit - «Enter» Select - «F» Filter - «E» Show parse errors",
|
||||
UiPage::Group => "«Q» Exit - «Enter» Select - «F» Filter - «G» Group By - «Esc» Back",
|
||||
UiPage::DistinctLogs => {
|
||||
"«Q» Exit - «F» Filter - «Esc» Back - «C» Copy log line - «G» Group By - «R» Show logs for request"
|
||||
"«Q» Exit - «F» Filter - «Esc» Back - «C» Copy log line - «Shift» + «C» Copy all lines - «G» Group By - «R» Show logs for request"
|
||||
}
|
||||
UiPage::ByRequest => {
|
||||
"«Q» Exit - «F» Filter - «Esc» Back - «C» Copy log line"
|
||||
"«Q» Exit - «F» Filter - «Esc» Back - «C» Copy log line - «Shift» + «C» Copy all lines"
|
||||
}
|
||||
UiPage::Log => {
|
||||
"«Q» Exit - «Esc» Back - «R» Toggle raw - «C» Copy log line - «R» Show logs for request"
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ pub enum UiEvent {
|
|||
SelectAt(usize),
|
||||
Enter(usize),
|
||||
Copy,
|
||||
CopyAll,
|
||||
EnterFilterMode,
|
||||
ClearFilter,
|
||||
Text(char),
|
||||
|
|
@ -53,6 +54,7 @@ pub fn handle_events(page: UiPage, ui_state: &UiState) -> io::Result<Option<UiEv
|
|||
(_, KeyCode::Home) => Some(UiEvent::Up(usize::MAX, false)),
|
||||
(_, KeyCode::Enter | KeyCode::Right) => Some(UiEvent::Select),
|
||||
(Mode::Normal, KeyCode::Char('c')) => Some(UiEvent::Copy),
|
||||
(Mode::Normal, KeyCode::Char('C')) => Some(UiEvent::CopyAll),
|
||||
(Mode::Normal, KeyCode::Char('r')) => Some(UiEvent::ByRequest),
|
||||
(Mode::Normal, KeyCode::Char('g')) => Some(UiEvent::GroupBy),
|
||||
(Mode::Normal, KeyCode::F(4) | KeyCode::Char('f')) => {
|
||||
|
|
|
|||
|
|
@ -56,7 +56,10 @@ impl StatefulWidget for SingleLog<'_> {
|
|||
|
||||
let layout = Layout::default()
|
||||
.direction(Direction::Vertical)
|
||||
.constraints(vec![Constraint::Min(par.line_count(area.width) as u16 + 1), Constraint::Percentage(100)])
|
||||
.constraints(vec![
|
||||
Constraint::Min(par.line_count(area.width) as u16 + 1),
|
||||
Constraint::Percentage(100),
|
||||
])
|
||||
.split(area);
|
||||
|
||||
par.render(layout[0], buf);
|
||||
|
|
@ -65,7 +68,10 @@ impl StatefulWidget for SingleLog<'_> {
|
|||
let (data_table, height) = render_data(line);
|
||||
let layout = Layout::default()
|
||||
.direction(Direction::Vertical)
|
||||
.constraints(vec![Constraint::Min(height + 2), Constraint::Percentage(100)])
|
||||
.constraints(vec![
|
||||
Constraint::Min(height + 2),
|
||||
Constraint::Percentage(100),
|
||||
])
|
||||
.split(layout[1]);
|
||||
|
||||
let block = Block::new()
|
||||
|
|
@ -206,27 +212,31 @@ fn find_path_prefix_length<'a, I: Iterator<Item = &'a str>>(paths: I) -> usize {
|
|||
}
|
||||
|
||||
pub fn render_data(log: &FullLogLine) -> (ScrollbarTable, u16) {
|
||||
let header = [
|
||||
Text::from("Key"),
|
||||
Text::from("Value"),
|
||||
]
|
||||
let header = [Text::from("Key"), Text::from("Value")]
|
||||
.into_iter()
|
||||
.map(Cell::from)
|
||||
.collect::<Row>()
|
||||
.style(TABLE_HEADER_STYLE)
|
||||
.height(1);
|
||||
|
||||
let max_key_width = log
|
||||
.data()
|
||||
.map(|(key, _)| key)
|
||||
.map(str::len)
|
||||
.max()
|
||||
.unwrap_or_default();
|
||||
let lines = log.data().count();
|
||||
|
||||
let max_key_width = log.data().map(|(key, _)| key).map(str::len).max().unwrap_or_default();
|
||||
let lines =log.data().count();
|
||||
|
||||
let rows = log.data()
|
||||
let rows = log
|
||||
.data()
|
||||
.map(|(key, value)| Row::new([Cell::new(Text::from(key)), Cell::new(Text::from(value))]));
|
||||
|
||||
|
||||
let widths = [
|
||||
Constraint::Min(max_key_width as u16),
|
||||
Constraint::Percentage(100),
|
||||
];
|
||||
(ScrollbarTable::new(rows, widths).header(header), lines as u16 + 1)
|
||||
(
|
||||
ScrollbarTable::new(rows, widths).header(header),
|
||||
lines as u16 + 1,
|
||||
)
|
||||
}
|
||||
|
|
@ -622,6 +622,17 @@ impl<'a> UiState<'a> {
|
|||
copy_osc(raw);
|
||||
(false, UiState::Distinct(state))
|
||||
}
|
||||
(UiState::Distinct(state), UiEvent::CopyAll) => {
|
||||
let mut lines = String::with_capacity(8 * 1024);
|
||||
|
||||
for line in &state.lines {
|
||||
let raw = app.get_source_line(line.line_number).unwrap_or_default();
|
||||
lines.push_str(raw);
|
||||
lines.push('\n');
|
||||
}
|
||||
copy_osc(&lines);
|
||||
(false, UiState::Distinct(state))
|
||||
}
|
||||
(UiState::Distinct(state), UiEvent::GroupBy) => (true, state.group_by_menu()),
|
||||
(UiState::Log(state), UiEvent::Copy) => {
|
||||
let raw = app
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue