mirror of
https://github.com/atuinsh/atuin.git
synced 2025-06-24 03:41:23 +02:00
Add xonsh support (#1375)
* Add basic xonsh support * Add init xonsh command * Add Xonsh install instructions in docs * Add xonsh ctrl-R search * update xonsh script and instructions Summary of changes: * Added duration to postcommand hook * Switched main search operation to use `subproccess.run()` rather than running as an xonsh shell command - this a) allows us to capture stderr without needing a temporary file and b) avoids a weird broken-buffer state that results from running a fullscreen TUI and then programmatically editing the buffer * Added support for immediately executing chosen command via `__atuin_accept__:` (like bash/zsh/fish) * strip newline from command before sending to atuin * Add basic xonsh support * Add init xonsh command * Add xonsh ctrl-R search * Remove advanced-install guide (was accidentally re-added during rebase) * Clean up Xonsh doesn't import private functions into the local namespace when sourcing a file * Add xonsh ro readme * Respect ATUIN_NOBIND * Format with black, and improve PEP8 compliance * Add up search * Format rust code --------- Co-authored-by: Joseph Montanaro <jfmonty2@gmail.com>
This commit is contained in:
parent
0faf414cd9
commit
c56f8ff736
@ -89,6 +89,7 @@ I wanted to. And I **really** don't want to.
|
|||||||
- bash
|
- bash
|
||||||
- fish
|
- fish
|
||||||
- nushell
|
- nushell
|
||||||
|
- xonsh
|
||||||
|
|
||||||
## Community
|
## Community
|
||||||
|
|
||||||
@ -327,6 +328,14 @@ Add to `config.nu`:
|
|||||||
source ~/.local/share/atuin/init.nu
|
source ~/.local/share/atuin/init.nu
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Xonsh
|
||||||
|
|
||||||
|
Add
|
||||||
|
```
|
||||||
|
execx($(atuin init xonsh))
|
||||||
|
```
|
||||||
|
to the end of your `~/.xonshrc`
|
||||||
|
|
||||||
# Contributors
|
# Contributors
|
||||||
|
|
||||||
<a href="https://github.com/atuinsh/atuin/graphs/contributors">
|
<a href="https://github.com/atuinsh/atuin/graphs/contributors">
|
||||||
|
@ -101,6 +101,11 @@ pub fn is_bash() -> bool {
|
|||||||
env::var("ATUIN_SHELL_BASH").is_ok()
|
env::var("ATUIN_SHELL_BASH").is_ok()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_xonsh() -> bool {
|
||||||
|
// only set on xonsh
|
||||||
|
env::var("ATUIN_SHELL_XONSH").is_ok()
|
||||||
|
}
|
||||||
|
|
||||||
/// Extension trait for anything that can behave like a string to make it easy to escape control
|
/// Extension trait for anything that can behave like a string to make it easy to escape control
|
||||||
/// characters.
|
/// characters.
|
||||||
///
|
///
|
||||||
|
@ -967,7 +967,9 @@ pub async fn history(
|
|||||||
match result {
|
match result {
|
||||||
InputAction::Accept(index) if index < results.len() => {
|
InputAction::Accept(index) if index < results.len() => {
|
||||||
let mut command = results.swap_remove(index).command;
|
let mut command = results.swap_remove(index).command;
|
||||||
if accept && (utils::is_zsh() || utils::is_fish() || utils::is_bash()) {
|
if accept
|
||||||
|
&& (utils::is_zsh() || utils::is_fish() || utils::is_bash() || utils::is_xonsh())
|
||||||
|
{
|
||||||
command = String::from("__atuin_accept__:") + &command;
|
command = String::from("__atuin_accept__:") + &command;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,6 +23,8 @@ pub enum Shell {
|
|||||||
Fish,
|
Fish,
|
||||||
/// Nu setup
|
/// Nu setup
|
||||||
Nu,
|
Nu,
|
||||||
|
/// Xonsh setup
|
||||||
|
Xonsh,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Cmd {
|
impl Cmd {
|
||||||
@ -140,12 +142,31 @@ bind -M insert \e\[A _atuin_bind_up";
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn init_xonsh(&self) {
|
||||||
|
let base = include_str!("../shell/atuin.xsh");
|
||||||
|
let (bind_ctrl_r, bind_up_arrow) = if std::env::var("ATUIN_NOBIND").is_ok() {
|
||||||
|
(false, false)
|
||||||
|
} else {
|
||||||
|
(!self.disable_ctrl_r, !self.disable_up_arrow)
|
||||||
|
};
|
||||||
|
println!(
|
||||||
|
"_ATUIN_BIND_CTRL_R={}",
|
||||||
|
if bind_ctrl_r { "True" } else { "False" }
|
||||||
|
);
|
||||||
|
println!(
|
||||||
|
"_ATUIN_BIND_UP_ARROW={}",
|
||||||
|
if bind_up_arrow { "True" } else { "False" }
|
||||||
|
);
|
||||||
|
println!("{base}");
|
||||||
|
}
|
||||||
|
|
||||||
pub fn run(self) {
|
pub fn run(self) {
|
||||||
match self.shell {
|
match self.shell {
|
||||||
Shell::Zsh => self.init_zsh(),
|
Shell::Zsh => self.init_zsh(),
|
||||||
Shell::Bash => self.init_bash(),
|
Shell::Bash => self.init_bash(),
|
||||||
Shell::Fish => self.init_fish(),
|
Shell::Fish => self.init_fish(),
|
||||||
Shell::Nu => self.init_nu(),
|
Shell::Nu => self.init_nu(),
|
||||||
|
Shell::Xonsh => self.init_xonsh(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
67
atuin/src/shell/atuin.xsh
Normal file
67
atuin/src/shell/atuin.xsh
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
import subprocess
|
||||||
|
from prompt_toolkit.keys import Keys
|
||||||
|
|
||||||
|
$ATUIN_SESSION=$(atuin uuid).rstrip('\n')
|
||||||
|
|
||||||
|
|
||||||
|
@events.on_precommand
|
||||||
|
def _atuin_precommand(cmd: str):
|
||||||
|
cmd = cmd.rstrip("\n")
|
||||||
|
$ATUIN_HISTORY_ID = $(atuin history start -- @(cmd)).rstrip("\n")
|
||||||
|
|
||||||
|
|
||||||
|
@events.on_postcommand
|
||||||
|
def _atuin_postcommand(cmd: str, rtn: int, out, ts):
|
||||||
|
if "ATUIN_HISTORY_ID" not in ${...}:
|
||||||
|
return
|
||||||
|
|
||||||
|
duration = ts[1] - ts[0]
|
||||||
|
# Duration is float representing seconds, but atuin expects integer of nanoseconds
|
||||||
|
nanos = round(duration * 10 ** 9)
|
||||||
|
with ${...}.swap(ATUIN_LOG="error"):
|
||||||
|
# This causes the entire .xonshrc to be re-executed, which is incredibly slow
|
||||||
|
# This happens when using a subshell and using output redirection at the same time
|
||||||
|
# For more details, see https://github.com/xonsh/xonsh/issues/5224
|
||||||
|
# (atuin history end --exit @(rtn) -- $ATUIN_HISTORY_ID &) > /dev/null 2>&1
|
||||||
|
atuin history end --exit @(rtn) --duration @(nanos) -- $ATUIN_HISTORY_ID > /dev/null 2>&1
|
||||||
|
del $ATUIN_HISTORY_ID
|
||||||
|
|
||||||
|
|
||||||
|
def _search(event, extra_args: list[str]):
|
||||||
|
buffer = event.current_buffer
|
||||||
|
cmd = ["atuin", "search", "--interactive", *extra_args, "--", buffer.text]
|
||||||
|
# We need to explicitly pass in xonsh env, in case user has set XDG_HOME or something else that matters
|
||||||
|
env = ${...}.detype()
|
||||||
|
env["ATUIN_SHELL_XONSH"] = "t"
|
||||||
|
|
||||||
|
p = subprocess.run(cmd, stderr=subprocess.PIPE, encoding="utf-8", env=env)
|
||||||
|
result = p.stderr.rstrip("\n")
|
||||||
|
# redraw prompt - necessary if atuin is configured to run inline, rather than fullscreen
|
||||||
|
event.cli.renderer.erase()
|
||||||
|
|
||||||
|
if not result:
|
||||||
|
return
|
||||||
|
|
||||||
|
buffer.reset()
|
||||||
|
if result.startswith("__atuin_accept__:"):
|
||||||
|
buffer.insert_text(result[17:])
|
||||||
|
buffer.validate_and_handle()
|
||||||
|
else:
|
||||||
|
buffer.insert_text(result)
|
||||||
|
|
||||||
|
|
||||||
|
@events.on_ptk_create
|
||||||
|
def _custom_keybindings(bindings, **kw):
|
||||||
|
@bindings.add(Keys.ControlR, filter=_ATUIN_BIND_CTRL_R)
|
||||||
|
def r_search(event):
|
||||||
|
_search(event, extra_args=[])
|
||||||
|
|
||||||
|
@bindings.add(Keys.Up, filter=_ATUIN_BIND_UP_ARROW)
|
||||||
|
def up_search(event):
|
||||||
|
# Only trigger if the buffer is a single line
|
||||||
|
if not '\n' in buffer.text:
|
||||||
|
_search(event, extra_args=["--shell-up-key-binding"])
|
||||||
|
return
|
||||||
|
|
||||||
|
# Run the default behavior for up arrow
|
||||||
|
event.current_buffer.auto_up(count=event.arg)
|
Loading…
x
Reference in New Issue
Block a user