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

Feature: Shortcut for opening a new pane in current working directory #102

Closed
kunalmohan opened this issue Dec 15, 2020 · 20 comments
Closed
Assignees
Labels
enhancement New feature or request

Comments

@kunalmohan
Copy link
Member

The new pane should be opened with the current working directory of the active pane instead of the default directory (/home/user in case of Linux)

use std::env;
let path = env::current_dir()?;

This should be helpful while implementing this feature.

@kunalmohan
Copy link
Member Author

I looked into this, we'll need to get the CWD of the active terminal using https://docs.rs/nix/0.11.0/nix/unistd/fn.getcwd.html instead of std::env and provide it to pty_bus while spawning a new terminal.

As I see it we have two implementation paths-

  1. StdinHandler -> Screen(GetCwd) -> PtyBus(SpawnTerminal) -> Screen(SpawnTerminal)
  2. PtyBus also stores the active pane RawFd at all times. So would reduce one step here.
    StdinHandler -> PtyBus(SpawnTerminalInCwd) -> Screen(SpawnTerminal)

@imsnif imsnif added the enhancement New feature or request label Dec 17, 2020
@imsnif
Copy link
Member

imsnif commented Dec 17, 2020

Option 2 seems good. Do you want to work on this, or shall I put a help wanted on it and someone will pick it up?

@kunalmohan
Copy link
Member Author

kunalmohan commented Dec 17, 2020

You can put up the label. I'll prefer working on tabs and persistent sessions first. And since this is relatively easy, this maybe good for new contributors as well.

@imsnif imsnif added the help wanted Extra attention is needed label Dec 17, 2020
@qrasmont
Copy link
Contributor

Hi, this seems like a good first issue and I would like to help. Can I go for it 😃 ?

@imsnif
Copy link
Member

imsnif commented Feb 10, 2021

Hi, this seems like a good first issue and I would like to help. Can I go for it smiley ?

You got it. :) Please feel free to reach out if you have any questions.

@imsnif imsnif removed the help wanted Extra attention is needed label Feb 10, 2021
@qrasmont
Copy link
Contributor

I do need a pointer. I found petty quick how create a new shortcut but what I have not yet found is where to call unistd::getcwd() from. Since unistd::getcwd() returns the cwd from the calling process, I would need to call it from the current active pane's process. And I saw as mentioned above that PtyBus stores the active pane RawFd.So I can't put the 2 together yet.

How do I go from knowing the RawFd of the active pane to calling unistd::getcwd() from whithin its process ? Any tip would be appreciated 👍.

@kunalmohan
Copy link
Member Author

Oops! Looks like I misread the docs for getcwd() earlier. I was under the impression that getcwd() would accept the RawFd as a parameter. I don't have another solution in my mind atm, so I guess we'll have to figure it out. I'll look for a solution and maybe you can help with that? (only if you want to, no pressure)
Sorry for the trouble!

@qrasmont
Copy link
Contributor

Sure I'll look into it !!

@qrasmont
Copy link
Contributor

Ok I think I have understood what has to happen. We basically need to know the active pane's child process forked pid to be able to get the cwd.

Fortunately it's already the case as every time the spawn_terminal function of os_input_output.rs is called it returns a tuple with the file descriptor and the forked pid (coming from nix's forkpty). For each PtyBus they are stored in the id_to_child_pid hashmap.

So for each PtyBus we know the forked pid, we can get the cwd from the proc filesystem

For example, the procinfo crate does this with its cwd(pid: pid_t) function, which does the following:

pub fn cwd(pid: pid_t) -> Result<PathBuf> {
    fs::read_link(format!("/proc/{}/cwd", pid))
}

So with the forked pid and the read_link function we can the cwd of the active pane.
What do you think ?

@imsnif
Copy link
Member

imsnif commented Feb 12, 2021

Good find! Just one consideration: if it's possible not to rely on an implementation from the proc filesystem that would be great (mac doesn't have it). But if that's the only way maybe this can be a linux feature for now.

@qrasmont
Copy link
Contributor

Good point!
It's funny, I looked at the existing crates that do cross platform proc utils and they have their pidcwd in ToDo for the macos target. Not sure if it is random or if there is a good reason for that (for example libproc, rust-psutil )

But the darwin-libproc crate has an implementation. I have a macos image in my files, I'll spawn a vm and test this.

The other solution I found is to call lsof, the following would work on both platform:

lsof -a -Fn -p $pid -d cwd | sed -e '1d' -e '2s/^n/'

But that's probably the last recourse option.

@kunalmohan
Copy link
Member Author

That's a great find! Though I am sceptical about whether we need the Pid from the forkpty result or the child process we spawn here. I think we'll need the latter, but not sure.

@qrasmont
Copy link
Contributor

You might be right. It'll need to be the correct one to have the correct behavior, so I'll make it work 👍

I have tested a get_cwd() implementation that works on both linux and mac. ☑️

There's one last thing I have troubles with and it is how the PtyBus bus stores the active pane RawFd. It stores the FDs of it's children but I don't see how I can know who is active from within PtyBus without getting the information from Screen

I looked into this, we'll need to get the CWD of the active terminal using https://docs.rs/nix/0.11.0/nix/unistd/fn.getcwd.html instead of std::env and provide it to pty_bus while spawning a new terminal.

As I see it we have two implementation paths-

  1. StdinHandler -> Screen(GetCwd) -> PtyBus(SpawnTerminal) -> Screen(SpawnTerminal)
  2. PtyBus also stores the active pane RawFd at all times. So would reduce one step here.
    StdinHandler -> PtyBus(SpawnTerminalInCwd) -> Screen(SpawnTerminal)

Basically from from your comment earlier @kunalmohan, I see how implementation 1 can be done, but not 2.
What am I missing?

@kunalmohan
Copy link
Member Author

Yeah, that's part of the issue. You'll have to add an active_pane: PaneId field to PtyBus and keep it updated, as we do in Tab(under Screen). So, the active_terminal under active_tab in Screen should be same as active_pane in PtyBus at all times. When the active_pane is of the type PaneId:::Terminal(..), we'll go ahead with get_cwd() otherwise we can ignore it and spawn a new pane normally.

@qrasmont
Copy link
Contributor

Ahah ok 😅, I thought it was already there hence my confusion!

@qrasmont
Copy link
Contributor

That's a great find! Though I am sceptical about whether we need the Pid from the forkpty result or the child process we spawn here. I think we'll need the latter, but not sure.

@kunalmohan you were right I do indeed need the PID from the spawned shell.
I think that to get that PID I need to setup some IPC between child/parent. I'm going to try to do that with a Sender/Receiver (like send_plugin_instructions/receive_pty_instructions in PtyBus) unless there is a better way I'm not aware of ?

@kunalmohan
Copy link
Member Author

Can we use stdin/stdout to convey the PID instead of establishing a new IPC channel for it?
If not, I'm curious as to how you plan to establish the IPC channel? One way would be to use https://docs.rs/ipmpsc/0.5.0/ipmpsc/struct.SharedRingBuffer.html#method.create_temp to create a temp channel and write the name (String) to child's stdin. Child would read the stdin before spawning the shell and create the Sender from it. Once shell is spawned, it sends shell's PID to parent.

@qrasmont
Copy link
Contributor

This is done! Sorry I took so long.
Still needs a bit of refactoring. The PR is imminent.

@fsevenm
Copy link

fsevenm commented Jun 4, 2021

It would be great if we have this feature in Zellij. For me, cd ~ is easier than cd up until reaching my project directory (again and again).

@a-kenji
Copy link
Contributor

a-kenji commented Sep 19, 2021

This has been implemented by #691 and is now standard behavior.

@a-kenji a-kenji closed this as completed Sep 19, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

5 participants