aboutsummaryrefslogtreecommitdiffstats
path: root/src/run/builtin.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/run/builtin.rs')
-rw-r--r--src/run/builtin.rs114
1 files changed, 95 insertions, 19 deletions
diff --git a/src/run/builtin.rs b/src/run/builtin.rs
index 507759f..2886d71 100644
--- a/src/run/builtin.rs
+++ b/src/run/builtin.rs
@@ -48,6 +48,7 @@ fn read_args<T: ArgParse>(args: &[BString], w: &mut dyn Write) -> std::result::R
Err(Error::Exit(-2))
}
+#[derive(Copy, Clone)]
pub struct cd;
impl Builtin for cd {
fn name(&self) -> &str {
@@ -91,6 +92,7 @@ impl Builtin for cd {
}
}
+#[derive(Copy, Clone)]
pub struct clear;
impl Builtin for clear {
fn name(&self) -> &str {
@@ -110,13 +112,14 @@ impl Builtin for clear {
}
/// restart shell
+#[derive(Copy, Clone)]
pub struct re;
impl Builtin for re {
fn name(&self) -> &str {
"re"
}
- fn special(&self, session: Arc<Mutex<Session>>, _args: &[BString]) {
+ fn special(&mut self, session: Arc<Mutex<Session>>, _args: &[BString]) {
session.lock().unwrap().raw.disable();
crate::reload::begin_reload();
session.lock().unwrap().raw.enable(); // something went wrong, let's restore raw mode
@@ -133,6 +136,7 @@ impl Builtin for re {
}
}
+#[derive(Copy, Clone)]
pub struct Sink {
name: &'static str,
append: bool,
@@ -168,6 +172,7 @@ pub const fn sink(name: &'static str, append: bool) -> Sink {
Sink { name, append }
}
+#[derive(Copy, Clone)]
pub struct from;
impl Builtin for from {
fn name(&self) -> &str {
@@ -191,6 +196,7 @@ impl Builtin for from {
}
}
+#[derive(Copy, Clone)]
pub struct _type;
impl Builtin for _type {
fn name(&self) -> &str {
@@ -227,6 +233,7 @@ impl Builtin for _type {
}
}
+#[derive(Copy, Clone)]
pub struct builtins;
impl Builtin for builtins {
fn name(&self) -> &str {
@@ -280,6 +287,7 @@ fn display_history<T: Iterator<Item = HistoryEntry>>(it: T, stdout: &mut dyn Wri
Ok(())
}
+#[derive(Copy, Clone)]
pub struct history;
impl Builtin for history {
fn name(&self) -> &str {
@@ -332,6 +340,7 @@ impl Builtin for history {
}
}
+#[derive(Copy, Clone)]
pub struct escape;
impl Builtin for escape {
fn name(&self) -> &str {
@@ -354,6 +363,7 @@ impl Builtin for escape {
}
}
+#[derive(Copy, Clone)]
pub struct parse;
impl Builtin for parse {
fn name(&self) -> &str {
@@ -383,6 +393,7 @@ impl Builtin for parse {
}
}
+#[derive(Copy, Clone)]
pub struct completion;
impl Builtin for completion {
fn name(&self) -> &str {
@@ -410,6 +421,7 @@ impl Builtin for completion {
}
}
+#[derive(Copy, Clone)]
pub struct null;
impl Builtin for null {
fn name(&self) -> &str {
@@ -428,6 +440,7 @@ impl Builtin for null {
}
}
+#[derive(Copy, Clone)]
pub struct var;
impl Builtin for var {
fn name(&self) -> &str {
@@ -456,6 +469,7 @@ impl Builtin for var {
}
}
+#[derive(Copy, Clone)]
pub struct alias;
impl Builtin for alias {
fn name(&self) -> &str {
@@ -517,6 +531,7 @@ impl Builtin for alias {
}
}
+#[derive(Copy, Clone)]
pub struct unalias;
impl Builtin for unalias {
fn name(&self) -> &str {
@@ -541,6 +556,7 @@ impl Builtin for unalias {
}
}
+#[derive(Copy, Clone)]
pub struct debug;
impl Builtin for debug {
fn name(&self) -> &str {
@@ -565,6 +581,7 @@ impl Builtin for debug {
}
}
+#[derive(Copy, Clone)]
pub struct terminfo;
impl Builtin for terminfo {
fn name(&self) -> &str {
@@ -602,12 +619,35 @@ impl Builtin for terminfo {
}
}
-pub struct bind;
+#[derive(Clone)]
+pub struct bind {
+ key: Option<crate::ansi::KbInput<'static>>,
+}
+
+impl bind {
+ pub const fn new() -> Self {
+ Self { key: None }
+ }
+
+ fn is_interactive(args: &[BString]) -> bool {
+ matches!(args.get(0).map(|x| &x[..]), Some(b"i" | b"interactive"))
+ }
+}
+
impl Builtin for bind {
fn name(&self) -> &str {
"bind"
}
+ fn special(&mut self, _session: Arc<Mutex<Session>>, args: &[BString]) {
+ if Self::is_interactive(args) {
+ let raw = crate::raw::ScopedRawMode::on_fd(0);
+ raw.enable();
+ self.key = crate::ansi::read(false);
+ raw.disable();
+ }
+ }
+
fn io(
&self,
session: Arc<Mutex<Session>>,
@@ -618,47 +658,78 @@ impl Builtin for bind {
let mut usage = || {
writeln!(
stdout,
- "usage: bind ti NAMED_KEYBIND COMMAND | bind key KEY COMMAND"
+ "usage: bind ti NAMED_KEYBIND COMMAND | bind key KEY COMMAND | bind [i|interactive]"
)?;
Err(Error::Exit(1))
};
- if args.len() < 3 {
+ if args.len() < 2 {
return usage();
}
let kind = &args[0];
- let key = &args[1];
- let cmd = &args[2];
- let args = &args[3..];
let mut se = session.lock().unwrap();
- let map = match &kind[..] {
- b"ti" => &mut se.ti_keybinds,
- b"key" => &mut se.ascii_keybinds,
- _ => return usage(),
+ let bind0 = |map: &mut HashMap<BString, _>, key: &[u8], cmd: &[BString]| {
+ map.insert(
+ key.to_vec(),
+ crate::parse::Command {
+ cmd: cmd[0].clone(),
+ args: cmd[1..].to_vec(),
+ },
+ );
+ };
+
+ let bind1 = |map: &mut HashMap<_, _>| {
+ bind0(map, &args[1], &args[2..]);
};
- map.insert(
- key.clone(),
- crate::parse::Command {
- cmd: cmd.clone(),
- args: args.to_vec(),
- },
- );
+ if Self::is_interactive(args) {
+ let Some(key) = self.key.as_ref() else {
+ writeln!(stdout, "no input available.")?;
+ return Err(Error::Exit(-1));
+ };
+
+ let x = match key {
+ ansi::KbInput::Escape(e) => {
+ bind0(&mut se.ascii_keybinds, e.keys[0].as_bytes(), &args[1..]);
+ format!("ti {}", e.keys[0])
+ }
+ _ => {
+ bind0(&mut se.ti_keybinds, key.as_bytes(), &args[1..]);
+ format!("key {}", key.as_bytes().escape_ascii())
+ }
+ };
+
+ // print what gets bound
+ write!(stdout, "bind {x} ")?;
+ for arg in args.iter().skip(1) {
+ stdout.write(&arg[..])?;
+ write!(stdout, " ")?;
+ }
+ writeln!(stdout)?;
+ return Ok(());
+ }
+
+ match &kind[..] {
+ b"ti" => bind1(&mut se.ti_keybinds),
+ b"key" => bind1(&mut se.ascii_keybinds),
+ _ => return usage(),
+ }
Ok(())
}
}
+#[derive(Clone)]
pub struct exit;
impl Builtin for exit {
fn name(&self) -> &str {
"exit"
}
- fn special(&self, _session: Arc<Mutex<Session>>, args: &[BString]) {
+ fn special(&mut self, _session: Arc<Mutex<Session>>, args: &[BString]) {
let exit_code: i32 = loop {
let Some(arg) = args.get(0) else {
break 0;
@@ -687,6 +758,7 @@ impl Builtin for exit {
}
/// control terminal
+#[derive(Copy, Clone)]
pub struct ct;
impl Builtin for ct {
fn name(&self) -> &str {
@@ -714,12 +786,16 @@ impl Builtin for ct {
b"cursor_right_word" => se.cursor_right_word(),
b"cursor_left_word" => se.cursor_left_word(),
b"prompt_clear" => se.prompt_clear(),
+ b"screen_clear" => se.screen_clear(),
b"complete" => {
drop(se);
Session::complete(session)
}
b"history_previous" => se.history_up(),
b"history_next" => se.history_down(),
+ b"prompt_del_left" => se.del_left(),
+ b"prompt_del_right" => se.del_right(),
+ b"prompt_del_left_or_previous" => se.del_left_or_previous(),
_ => return Err(Error::Exit(-2)),
}