zellij/zellij-utils/src/cli.rs
Aram Drevekenin c64bf5207a
feat(ux): rerun command pane (#1787)
* chore(config): default kdl keybindings config

* tests

* work

* refactor(config): move stuff around

* work

* tab merge layout

* work

* work

* layouts working

* work

* layout tests

* work

* work

* feat(parsing): kdl layouts without config

* refactor(kdl): move stuff around

* work

* tests(layout): add cases and fix bugs

* work

* fix(kdl): various bugs

* chore(layouts): move all layouts to kdl

* feat(kdl): shared keybidns

* fix(layout): do not count fixed panes toward percentile

* fix(keybinds): missing keybinds and actions

* fix(config): adjust default tips

* refactor(config): move stuff around

* fix(tests): make e2e tests pass

* fix(kdl): add verbose parsing errors

* fix(kdl): focused tab

* fix(layout): corret default_tab_template behavior

* style(code): fix compile warnings

* feat(cli): send actions through the cli

* fix(cli): exit only when action is done

* fix(cli): open embedded pane from floating pane

* fix(cli): send actions to other sessions

* feat(cli): command alias

* feat(converter): convert old config

* feat(converter): convert old layout and theme files

* feat(kdl): pretty errors

* feat(client): convert old YAML files on startup

* fix: various bugs and styling issues

* fix: e2e tests

* fix(screen): propagate errors after merge

* style(clippy): lower clippy level

* fix(tests): own session_name variable

* style(fmt): rustfmt

* fix(cli): various action fixes

* style(fmt): rustfmt

* fix(themes): loading of theme files

* style(fmt): rustfmt

* fix(tests): theme fixtures

* fix(layouts): better errors on unknown nodes

* fix(kdl): clarify valid node terminator error

* fix(e2e): adjust close tab test

* fix(e2e): adjust close tab test again

* style(code): cleanup some comments

* get command panes not to exit on command exit

* separate terminal pane_ids from raw_fds

* render frame according to exit status

* re-run command on enter and close pane on ctrl-c

* proper error when command is not found

* make ui nicer

* initial pane title for command panes

* fix pane override bug

* reap terminal_ids from os_input_output on pane close

* bool floating flag

* some ui tweaks

* fix tests

* make rustfmt happy

* e2e test for command pane

* fix various concurrency issues

* rename command to run in the cli

* rustfmt

* style(fmt): rustfmt

* fix(e2e): command => run

* fix(e2e): command => run in snapshot too!
2022-10-11 16:45:46 +02:00

257 lines
8.5 KiB
Rust

use crate::data::InputMode;
use crate::setup::Setup;
use crate::{
consts::{ZELLIJ_CONFIG_DIR_ENV, ZELLIJ_CONFIG_FILE_ENV},
input::actions::{Direction, ResizeDirection},
input::options::CliOptions,
};
use clap::{Parser, Subcommand};
use serde::{Deserialize, Serialize};
use std::path::PathBuf;
#[derive(Parser, Default, Debug, Clone, Serialize, Deserialize)]
#[clap(version, name = "zellij")]
pub struct CliArgs {
/// Maximum panes on screen, caution: opening more panes will close old ones
#[clap(long, value_parser)]
pub max_panes: Option<usize>,
/// Change where zellij looks for plugins
#[clap(long, value_parser, overrides_with = "data_dir")]
pub data_dir: Option<PathBuf>,
/// Run server listening at the specified socket path
#[clap(long, value_parser, hide = true, overrides_with = "server")]
pub server: Option<PathBuf>,
/// Specify name of a new session
#[clap(long, short, overrides_with = "session", value_parser)]
pub session: Option<String>,
/// Name of a predefined layout inside the layout directory or the path to a layout file
#[clap(short, long, value_parser, overrides_with = "layout")]
pub layout: Option<PathBuf>,
/// Change where zellij looks for the configuration file
#[clap(short, long, overrides_with = "config", env = ZELLIJ_CONFIG_FILE_ENV, value_parser)]
pub config: Option<PathBuf>,
/// Change where zellij looks for the configuration directory
#[clap(long, overrides_with = "config_dir", env = ZELLIJ_CONFIG_DIR_ENV, value_parser)]
pub config_dir: Option<PathBuf>,
#[clap(subcommand)]
pub command: Option<Command>,
/// Specify emitting additional debug information
#[clap(short, long, value_parser)]
pub debug: bool,
}
impl CliArgs {
pub fn should_clean_config(&self) -> bool {
match &self.command {
Some(Command::Setup(ref setup)) => setup.clean,
_ => false,
}
}
}
#[derive(Debug, Subcommand, Clone, Serialize, Deserialize)]
pub enum Command {
/// Change the behaviour of zellij
#[clap(name = "options", value_parser)]
Options(CliOptions),
/// Setup zellij and check its configuration
#[clap(name = "setup", value_parser)]
Setup(Setup),
/// Explore existing zellij sessions
#[clap(flatten)]
Sessions(Sessions),
}
#[derive(Debug, Subcommand, Clone, Serialize, Deserialize)]
pub enum SessionCommand {
/// Change the behaviour of zellij
#[clap(name = "options")]
Options(CliOptions),
}
#[derive(Debug, Subcommand, Clone, Serialize, Deserialize)]
pub enum Sessions {
/// List active sessions
#[clap(visible_alias = "ls")]
ListSessions,
/// Attach to a session
#[clap(visible_alias = "a")]
Attach {
/// Name of the session to attach to.
#[clap(value_parser)]
session_name: Option<String>,
/// Create a session if one does not exist.
#[clap(short, long, value_parser)]
create: bool,
/// Number of the session index in the active sessions ordered creation date.
#[clap(long, value_parser)]
index: Option<usize>,
/// Change the behaviour of zellij
#[clap(subcommand, name = "options")]
options: Option<Box<SessionCommand>>,
},
/// Kill the specific session
#[clap(visible_alias = "k")]
KillSession {
/// Name of target session
#[clap(value_parser)]
target_session: Option<String>,
},
/// Kill all sessions
#[clap(visible_alias = "ka")]
KillAllSessions {
/// Automatic yes to prompts
#[clap(short, long, value_parser)]
yes: bool,
},
/// Send actions to a specific session
#[clap(visible_alias = "ac")]
#[clap(subcommand)]
Action(CliAction),
/// Run a command in a new pane
#[clap(visible_alias = "r")]
Run {
command: Option<String>,
#[clap(short, long, value_parser, conflicts_with("floating"))]
direction: Option<Direction>,
#[clap(long, value_parser)]
cwd: Option<PathBuf>,
#[clap(short, long, value_parser, default_value("false"), takes_value(false))]
floating: bool,
},
/// Edit file with default $EDITOR / $VISUAL
#[clap(visible_alias = "e")]
Edit {
file: PathBuf,
#[clap(short, long, value_parser)]
line_number: Option<usize>,
#[clap(short, long, value_parser, conflicts_with("floating"))]
direction: Option<Direction>,
#[clap(short, long, value_parser, default_value("false"), takes_value(false))]
floating: bool,
},
ConvertConfig {
old_config_file: PathBuf,
},
ConvertLayout {
old_layout_file: PathBuf,
},
ConvertTheme {
old_theme_file: PathBuf,
},
}
#[derive(Debug, Subcommand, Clone, Serialize, Deserialize)]
pub enum CliAction {
/// Write bytes to the terminal.
Write { bytes: Vec<u8> },
/// Write characters to the terminal.
WriteChars { chars: String },
/// Resize the focused pane in the specified direction. [right|left|up|down|+|-]
Resize { resize_direction: ResizeDirection },
/// Change focus to the next pane
FocusNextPane,
/// Change focus to the previous pane
FocusPreviousPane,
/// Move the focused pane in the specified direction. [right|left|up|down]
MoveFocus { direction: Direction },
/// Move focus to the pane or tab (if on screen edge) in the specified direction
/// [right|left|up|down]
MoveFocusOrTab { direction: Direction },
/// Change the location of the focused pane in the specified direction
/// [right|left|up|down]
MovePane { direction: Direction },
/// Dumps the pane scrollback to a file
DumpScreen { path: PathBuf },
/// Open the pane scrollback in your default editor
EditScrollback,
/// Scroll up in the focused pane
ScrollUp,
/// Scroll down in focus pane.
ScrollDown,
/// Scroll down to bottom in focus pane.
ScrollToBottom,
/// Scroll up one page in focus pane.
PageScrollUp,
/// Scroll down one page in focus pane.
PageScrollDown,
/// Scroll up half page in focus pane.
HalfPageScrollUp,
/// Scroll down half page in focus pane.
HalfPageScrollDown,
/// Toggle between fullscreen focus pane and normal layout.
ToggleFullscreen,
/// Toggle frames around panes in the UI
TogglePaneFrames,
/// Toggle between sending text commands to all panes on the current tab and normal mode.
ToggleActiveSyncTab,
/// Open a new pane in the specified direction [right|down]
/// If no direction is specified, will try to use the biggest available space.
NewPane {
#[clap(short, long, value_parser, conflicts_with("floating"))]
direction: Option<Direction>,
#[clap(short, long, value_parser)]
command: Option<String>,
#[clap(long, value_parser)]
cwd: Option<PathBuf>,
#[clap(short, long, value_parser, default_value("false"), takes_value(false))]
floating: bool,
},
/// Open the specified file in a new zellij pane with your default EDITOR
Edit {
file: PathBuf,
#[clap(short, long, value_parser, conflicts_with("floating"))]
direction: Option<Direction>,
#[clap(short, long, value_parser)]
line_number: Option<usize>,
#[clap(short, long, value_parser, default_value("false"), takes_value(false))]
floating: bool,
},
/// Switch input mode of all connected clients [locked|pane|tab|resize|move|search|session]
SwitchMode { input_mode: InputMode },
/// Embed focused pane if floating or float focused pane if embedded
TogglePaneEmbedOrFloating,
/// Toggle the visibility of all fdirectionloating panes in the current Tab, open one if none exist
ToggleFloatingPanes,
/// Close the focused pane.
ClosePane,
/// Renames the focused pane
RenamePane { name: String },
/// Remove a previously set pane name
UndoRenamePane,
/// Go to the next tab.
GoToNextTab,
/// Go to the previous tab.
GoToPreviousTab,
/// Close the current tab.
CloseTab,
/// Go to tab with index [index]
GoToTab { index: u32 },
/// Renames the focused pane
RenameTab { name: String },
/// Remove a previously set tab name
UndoRenameTab,
/// Create a new tab, optionally with a specified tab layout and name
NewTab {
#[clap(short, long, value_parser)]
layout: Option<PathBuf>,
#[clap(short, long, value_parser)]
name: Option<String>,
},
}