Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open in directory of current process #5

Open
nsbgn opened this issue Dec 23, 2021 · 2 comments
Open

Open in directory of current process #5

nsbgn opened this issue Dec 23, 2021 · 2 comments

Comments

@nsbgn
Copy link

nsbgn commented Dec 23, 2021

The urxvt extension you wrote for opening a terminal in the same directory (cf https://raphael.medaer.me/2019/06/21/urxvt-open-current-wd.html) works pretty well, even with the daemon-client structure, and is indeed a better solution than X11 hacks. Thanks a lot!

However, when the shell process forks, the working directory does not change together with the working directory of the child process. While that is sometimes desired behaviour (eg when having spawned a GUI app or some other background process), I often actually do want to use the cwd of the child process. This is usually for TUIs like vim or lf.

If this sounds like a good feature, I'd be happy to give it a shot myself and PR. (In that case, do you mind if I also copy your code into a dedicated repository?)

I don't know Perl, but I'm thinking that it could be achieved by examining Proc::ProcessTable for the most recent child process with a particular name (lf and nvim, in my case). To illustrate, the following does seem to work:

sub on_init {
    my ($self) = @_;
    my $pid;
    tie $pid, 'IPC::Shareable', $glue, { %options };

    if (defined $pid and $pid ne "") {
        my $link = sprintf "/proc/%d/cwd", $pid;
        my $wd = readlink $link;

        my @procs = qw();
        push @procs, $pid;
        my $pt = Proc::ProcessTable->new();
        for my $p ( @{$pt->table} ){
            my $name = $p->{fname};
            if (is_element_of($p->{ppid}, @procs) && (
                    $name == 'lf' || $name == 'nvim'
                )){
                push @procs, $p->{pid};
                $wd = $p->{cwd};
            }
        }

        if (-e $wd) {
            $self->resource("chdir", $wd);
        }
    }
}

However, it does feel rather hacky, so I'm curious what your thoughts are. Is there a better way?

If no better solution presents itself, I'll probably do something like this, but pull the names of the binaries from an environment variable, and only load the process table if that environment variable is non-empty.

@rmedaer
Copy link
Owner

rmedaer commented Jan 3, 2022

Hi @slakkenhuis, many thanks for your feedback.

do you mind if I also copy your code into a dedicated repository?

No, go ahead! Please let me know the URL of this brand new repository so I can edit my post.

However, it does feel rather hacky, so I'm curious what your thoughts are. Is there a better way?

To be honest, I'm not a Perl expert but I think you could also find the proc name through /proc/%d/cmdline.

@nsbgn
Copy link
Author

nsbgn commented Jan 5, 2022

Thanks! I took a look at how tmux does this. They use tcgetpgrp to find the foreground process, which is clearly superior to sifting through the whole process table. I thought it was straightforward to do the same in your extension:

use POSIX qw/tcgetpgrp/;

sub on_init {
    my ($self) = @_;
    my $pid;
    tie $pid, 'IPC::Shareable', $glue, { %options };

    if (defined $pid and $pid ne "") {
        my $ptyfd = readlink(sprintf "/proc/%d/fd/1", $pid);
        if (open(TTY, $ptyfd)) {
            my $fgpid = tcgetpgrp(fileno(*TTY));
            if ($fgpid eq -1){
                $fgpid = $pid;
            }
            close TTY;
        }
        my $wd = readlink(sprintf("/proc/%d/cwd", $fgpid));
        if (-e $wd) {
            $self->resource("chdir", $wd);
        }
    }
}

Alas, that doesn't work. I think that tcgetpgrp can only get the foreground process if the requesting process is attached to the same pty (for security). Therefore, I fell back to using the ps shell program. Someone with more Perl know-how might know how to improve it.

    my $tpgid = qx/ps p $pid -o tpgid=/;

I put the repo at https://github.com/slakkenhuis/urxvt-cwd. Comments welcome :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants