mirror of
https://github.com/wez/wezterm.git
synced 2024-11-22 22:42:48 +03:00
add cli command to list tabs
This commit is contained in:
parent
a6ff84a268
commit
1d44098747
@ -39,6 +39,7 @@ rayon = "1.0"
|
||||
serde = {version="1.0", features = ["rc"]}
|
||||
serde_derive = "1.0"
|
||||
structopt = "0.2"
|
||||
tabout = { path = "tabout" }
|
||||
term = { path = "term" }
|
||||
termwiz = { path = "termwiz"}
|
||||
toml = "0.4"
|
||||
|
56
src/main.rs
56
src/main.rs
@ -5,6 +5,7 @@ use failure::Error;
|
||||
use log::{error, info};
|
||||
use std::ffi::OsString;
|
||||
use structopt::StructOpt;
|
||||
use tabout::{tabulate_output, Alignment, Column};
|
||||
|
||||
use std::rc::Rc;
|
||||
use std::sync::Arc;
|
||||
@ -115,7 +116,17 @@ enum SubCommand {
|
||||
}
|
||||
|
||||
#[derive(Debug, StructOpt, Clone)]
|
||||
struct CliCommand {}
|
||||
struct CliCommand {
|
||||
#[structopt(subcommand)]
|
||||
sub: CliSubCommand,
|
||||
}
|
||||
|
||||
#[derive(Debug, StructOpt, Clone)]
|
||||
enum CliSubCommand {
|
||||
#[structopt(name = "list", about = "list windows and tabs")]
|
||||
#[structopt(raw(setting = "structopt::clap::AppSettings::ColoredHelp"))]
|
||||
List,
|
||||
}
|
||||
|
||||
fn run_terminal_gui(config: Arc<config::Config>, opts: &StartCommand) -> Result<(), Error> {
|
||||
let font_system = opts.font_system.unwrap_or(config.font_system);
|
||||
@ -193,23 +204,36 @@ fn main() -> Result<(), Error> {
|
||||
error!("Using configuration: {:#?}\nopts: {:#?}", config, opts);
|
||||
run_terminal_gui(config, &start)
|
||||
}
|
||||
SubCommand::Cli(_) => {
|
||||
use crate::server::codec::*;
|
||||
SubCommand::Cli(cli) => {
|
||||
let mut client = Client::new(&config)?;
|
||||
info!("ping: {:?}", client.ping()?);
|
||||
let tabs = client.list_tabs()?;
|
||||
for entry in tabs.tabs.iter() {
|
||||
info!("tab {} {}: {}", entry.window_id, entry.tab_id, entry.title);
|
||||
match cli.sub {
|
||||
CliSubCommand::List => {
|
||||
let cols = vec![
|
||||
Column {
|
||||
name: "WINID".to_string(),
|
||||
alignment: Alignment::Right,
|
||||
},
|
||||
Column {
|
||||
name: "TABID".to_string(),
|
||||
alignment: Alignment::Right,
|
||||
},
|
||||
Column {
|
||||
name: "TITLE".to_string(),
|
||||
alignment: Alignment::Left,
|
||||
},
|
||||
];
|
||||
let mut data = vec![];
|
||||
let tabs = client.list_tabs()?;
|
||||
for entry in tabs.tabs.iter() {
|
||||
data.push(vec![
|
||||
entry.window_id.to_string(),
|
||||
entry.tab_id.to_string(),
|
||||
entry.title.clone(),
|
||||
]);
|
||||
}
|
||||
tabulate_output(&cols, &data, &mut std::io::stdout().lock())?;
|
||||
}
|
||||
}
|
||||
error!(
|
||||
"spawn: {:?}",
|
||||
client.spawn(Spawn {
|
||||
domain_id: 0,
|
||||
size: PtySize::default(),
|
||||
command: None,
|
||||
window_id: None,
|
||||
})
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
12
tabout/Cargo.toml
Normal file
12
tabout/Cargo.toml
Normal file
@ -0,0 +1,12 @@
|
||||
[package]
|
||||
name = "tabout"
|
||||
version = "0.1.0"
|
||||
authors = ["Wez Furlong <wez@wezfurlong.org>"]
|
||||
edition = "2018"
|
||||
repository = "https://github.com/wez/wezterm"
|
||||
description = "Tabulate output for CLI programs"
|
||||
license = "MIT"
|
||||
documentation = "https://docs.rs/tabout"
|
||||
|
||||
[dependencies]
|
||||
termwiz = { path = "../termwiz"}
|
151
tabout/src/lib.rs
Normal file
151
tabout/src/lib.rs
Normal file
@ -0,0 +1,151 @@
|
||||
//! This crate provides some helpers to automatically tabulate data
|
||||
//! so that it is presented reasonably nicely for humans to read,
|
||||
//! without requiring that each column be hard coded to particular
|
||||
//! widths in the code beforehand.
|
||||
|
||||
/// Describes the alignment of a column
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum Alignment {
|
||||
Left,
|
||||
Center,
|
||||
Right,
|
||||
}
|
||||
|
||||
/// Describes a column
|
||||
#[derive(Debug)]
|
||||
pub struct Column {
|
||||
/// The name of the column; this is the column header text
|
||||
pub name: String,
|
||||
/// How the column should be aligned
|
||||
pub alignment: Alignment,
|
||||
}
|
||||
|
||||
fn emit_column<W: std::io::Write>(
|
||||
text: &str,
|
||||
max_width: usize,
|
||||
alignment: Alignment,
|
||||
output: &mut W,
|
||||
) -> Result<(), std::io::Error> {
|
||||
let (left_pad, right_pad) = match alignment {
|
||||
Alignment::Left => (0, max_width - text.len()),
|
||||
Alignment::Center => {
|
||||
let left_pad = (max_width - text.len()) / 2;
|
||||
// for odd-length columns, take care to use the remaining
|
||||
// length rather than just assuming that the right_pad
|
||||
// will have the same value as the left_pad
|
||||
let right_pad = max_width - (text.len() + left_pad);
|
||||
(left_pad, right_pad)
|
||||
}
|
||||
Alignment::Right => (max_width - text.len(), 0),
|
||||
};
|
||||
|
||||
for _ in 0..left_pad {
|
||||
write!(output, " ")?;
|
||||
}
|
||||
write!(output, "{}", text)?;
|
||||
for _ in 0..right_pad {
|
||||
write!(output, " ")?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Given a set of column headers and the row content,
|
||||
/// automatically compute the column widths and then format
|
||||
/// the data to the output stream.
|
||||
/// If a given row has more columns than are defined in the
|
||||
/// columns slice, then a left aligned column with no label
|
||||
/// will be assumed.
|
||||
pub fn tabulate_output<S: std::string::ToString, W: std::io::Write>(
|
||||
columns: &[Column],
|
||||
rows: &Vec<Vec<S>>,
|
||||
output: &mut W,
|
||||
) -> Result<(), std::io::Error> {
|
||||
let mut col_widths: Vec<usize> = columns.iter().map(|c| c.name.len()).collect();
|
||||
|
||||
let mut display_rows: Vec<Vec<String>> = vec![];
|
||||
for src_row in rows {
|
||||
let dest_row: Vec<String> = src_row.iter().map(|col| col.to_string()).collect();
|
||||
for (idx, col) in dest_row.iter().enumerate() {
|
||||
if let Some(width) = col_widths.get_mut(idx) {
|
||||
*width = (*width).max(col.len());
|
||||
} else {
|
||||
col_widths.push(col.len());
|
||||
}
|
||||
}
|
||||
display_rows.push(dest_row);
|
||||
}
|
||||
|
||||
for (idx, col) in columns.iter().enumerate() {
|
||||
if idx > 0 {
|
||||
write!(output, " ")?;
|
||||
}
|
||||
|
||||
emit_column(&col.name, col_widths[idx], col.alignment, output)?;
|
||||
}
|
||||
write!(output, "\n")?;
|
||||
|
||||
for row in &display_rows {
|
||||
for (idx, col) in row.iter().enumerate() {
|
||||
let max_width = col_widths.get(idx).cloned().unwrap_or(col.len());
|
||||
let alignment = columns
|
||||
.get(idx)
|
||||
.map(|c| c.alignment)
|
||||
.unwrap_or(Alignment::Left);
|
||||
|
||||
if idx > 0 {
|
||||
write!(output, " ")?;
|
||||
}
|
||||
|
||||
emit_column(col, max_width, alignment, output)?;
|
||||
}
|
||||
write!(output, "\n")?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// A convenience around `tabulate_output` that returns a String holding
|
||||
/// the formatted data.
|
||||
pub fn tabulate_output_as_string<S: std::string::ToString>(
|
||||
columns: &[Column],
|
||||
rows: &Vec<Vec<S>>,
|
||||
) -> Result<String, std::io::Error> {
|
||||
let mut output: Vec<u8> = vec![];
|
||||
tabulate_output(columns, rows, &mut output)?;
|
||||
String::from_utf8(output)
|
||||
.map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, format!("{}", e)))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn basics() {
|
||||
let cols = vec![
|
||||
Column {
|
||||
name: "hello".to_string(),
|
||||
alignment: Alignment::Left,
|
||||
},
|
||||
Column {
|
||||
name: "middle-of-me".to_string(),
|
||||
alignment: Alignment::Center,
|
||||
},
|
||||
Column {
|
||||
name: "world".to_string(),
|
||||
alignment: Alignment::Right,
|
||||
},
|
||||
];
|
||||
let data = vec![vec!["one", "i", "two"], vec!["longer", "boo", "again"]];
|
||||
|
||||
let output = tabulate_output_as_string(&cols, &data).unwrap();
|
||||
eprintln!("output is:\n{}", output);
|
||||
assert_eq!(
|
||||
output,
|
||||
"hello middle-of-me world\n\
|
||||
one i two\n\
|
||||
longer boo again\n"
|
||||
);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user