matklad / xshell

Apache License 2.0
695 stars 28 forks source link

xshell command fails to communicate with a running app #68

Closed azzamsa closed 1 year ago

azzamsa commented 1 year ago

Hi.

with inspiration from matklad/config/xtool. I have ported all my rust-script scripts and bash script to a cargo project.

However, I am having a hard time porting my termhere script. the xshell version fails to open a new tab in Zellij Action.

This is the original script:

#!/bin/sh

# takes the path as an argument (e.g. /opt)
if [ -n "$1" ]; then
  path="$1"
else
  echo "::: No path passed. Use '$HOME' as default"
  path="$HOME"
fi

zellij action new-tab --layout "default" --cwd "$path"

The xshell version

use xshell::{cmd, Shell};

fn home() -> anyhow::Result<String> {
    Ok(std::env::var("HOME")?)
}

fn here(sh: &Shell, pwd: &str) -> anyhow::Result<()> {
    let args = ["--layout", "default", "--cwd", pwd];
    println!("Opening terminal in `{pwd}`");
    cmd!(sh, "zellij action new-tab {args...}").run()?;
    Ok(())
}

pub(crate) fn run(sh: &Shell) -> anyhow::Result<()> {
    let flags = xflags::parse_or_exit! {
        optional pwd: String
    };

    match flags.pwd {
        Some(p) => here(sh, &p)?,
        None => here(sh, &home()?)?,
    };

    Ok(())
}

Both scripts run fine if executed directly in the terminal. but the xshell version can't work inside the emacs function (which is my primary workflow). However, the (b)ash version works well:

(defun terminal-here ()
  "Open a new terminal with current directory as PWD"
  (interactive)
  (message "Opening terminal in %s" default-directory)
  ;; Need to use `expand-file-name` to expand `~` into a full path
  ;; Otherwise, termhere fallback to `$HOME`
  (start-process "" nil "termhere"  (expand-file-name default-directory)))

Any idea how to debug this issue?

Thanks for xshell :heart:

lnicola commented 1 year ago

My go-to tool for this is strace, e.g. sudo strace -e execve,execveat -s1024 -fp $(pidof emacs).

azzamsa commented 1 year ago

@lnicola TIL.

strace: Process 447585 attached with 4 threads
[pid 447585] --- SIGIO {si_signo=SIGIO, si_code=SI_KERNEL} ---
strace: Process 473783 attached
[pid 473783] execve("/var/home/user/.local/bin/termhere", ["/var/home/user/.local/bin/termhere", "/var/home/user/dotfiles/"], 0x1719ca0 /* 83 vars */) = 0
[pid 473783] +++ exited with 1 +++
[pid 447585] --- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=473783, si_uid=1000, si_status=1, si_utime=0, si_stime=0} ---
[pid 447585] --- SIGIO {si_signo=SIGIO, si_code=SI_KERNEL} ---
[pid 447585] --- SIGIO {si_signo=SIGIO, si_code=SI_TKILL, si_pid=447585, si_uid=1000} ---
[pid 447585] --- SIGIO {si_signo=SIGIO, si_code=SI_TKILL, si_pid=447585, si_uid=1000} ---
[pid 447585] --- SIGIO {si_signo=SIGIO, si_code=SI_KERNEL} ---
[pid 447585] --- SIGIO {si_signo=SIGIO, si_code=SI_KERNEL} ---
strace: Process 474239 attached
[pid 474239] execve("/var/home/user/.local/bin/termohere", ["/var/home/user/.local/bin/termohere", "/var/home/user/.config/doom/"], 0x1719ca0 /* 83 vars */) = 0
strace: Process 474240 attached
[pid 474240] execve("/var/home/user/.local/share/cargo/bin/zellij", ["zellij", "action", "new-tab", "--layout", "default", "--cwd", "/var/home/user/.config/doom/"], 0x557ea89e6390 /* 83 vars */) = 0
[pid 447585] --- SIGIO {si_signo=SIGIO, si_code=SI_KERNEL} ---
[pid 474240] +++ exited with 0 +++
[pid 474239] --- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=474240, si_uid=1000, si_status=0, si_utime=0, si_stime=0} ---
[pid 474239] +++ exited with 0 +++
[pid 447585] --- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=474239, si_uid=1000, si_status=0, si_utime=0, si_stime=0} ---
[pid 447588] --- SIGIO {si_signo=SIGIO, si_code=SI_KERNEL} ---
[pid 447585] --- SIGIO {si_signo=SIGIO, si_code=SI_TKILL, si_pid=447585, si_uid=1000} ---

So strange, the xshell version doesn't execute zellij as the bash version. I need to investigate further about this line [pid 473783] +++ exited with 1 +++ in the xshell version.

Any suggestion for further debugging?

lnicola commented 1 year ago

Maybe parse_or_exit! quits? It seems a bit strange, especially if you're saying it works from a terminal. Maybe try sprinkling std::process::exit(2), std::process::exit(3) statements in your code to see where it's exiting.

azzamsa commented 1 year ago

I think it has something to do with the shell.

Running the xshell version from the emacs function / ielm doesn't work, but the strange thing is that it works it executed from shell-command.

I think it has to do with the shell. Because zellij is running from the shell, I think the shell knows its pid (?)

azzamsa commented 1 year ago

Solved. :tada:


As I mention previously, it has to do with the shell. That's why (start-process "" nil "termhere" "~/.tmp") dosen't work but (shell-command "termhere /opt") works.

These are my observations:

ELISP> (start-process "" nil "termhere" "~/.tmp") ❌
#<process >

ELISP> (shell-command "termhere /opt") ✅
0 (#o0, #x0, ?\C-@)

ELISP>  (async-shell-command "termhere ~/.tmp")  ✅
#<window 21 on *Async Shell Command*>

So, my go to solution is async-shell-command, but it print the output to a new buffer. So I need to use call-process-shell-command.

This is my final solution:

-  ;; Otherwise, termhere fallback to `$HOME`
-  (start-process "" nil "termhere"  (expand-file-name default-directory)))
+  ;; Otherwise, termhere fallback to `$HOME`
+  ;; The Rust version of `termhere' only works with `call-process-shell-command',
+  ;; `async-shell-command', and `shell-command'. But the (b)ash version works
+  ;; out of the box. Including with `start-process'
+  (call-process-shell-command (concat "termhere " (expand-file-name default-directory))))

Thank you so much for help @lnicola :heart: