Terminal: Open new terminal tab in same directory as existing tab (OSC 7?)

Created on 11 Oct 2019  ·  39Comments  ·  Source: microsoft/terminal

Description of the new feature/enhancement

Have the option (or default) of a new terminal tab opening in the current directory of the window of which you hit the hotkey to open a new tab. This is the standard way most linux terminals work and is most handy. I often work in a directory where I need to launch multiple seperate processes, its a pain to CD back into the directory each time.

Proposed technical implementation details (optional)

Hit the new tab hotkey, the new terminal should then be in the same folder as the previouse.

Area-Settings Area-VT In-PR Issue-Feature Product-Conpty Product-Powershell Product-Terminal

Most helpful comment

This is a crucial missing feature.

All 39 comments

There's a "standard" escape sequence (OSC 7 ; URI ST) to set the terminal emulator's belief about the current directory. It originates from macOS Terminal.app, and was later adopted by some other ones, including GNOME Terminal and as far as I know Konsole too.

Another possible approach is to do some OS-specific hacks to examine the inner state of the child process (or even further down to descendents).

Yet another possibility is to mix the two, e.g. go to the directory set via OSC 7 if it was ever emitted, otherwise dig into the process.

The advantage of the OSC 7 approach is that it's clever regarding when to and when not to follow a child process. E.g. you start another nested subshell, it'll be the subdirectory of that subshell that's taken into account because that one also emits this sequence. However, launch an app that internally changes directory (e.g. make) and it – luckily – won't be make's internal subdir that's used.

The disadvantage of OSC 7 is that it requires cooperation from the shell, or other apps that matter.

I've been rejecting this feature request for as long as this project has been open-source, and I never learned about OSC 7. This is _very exciting._

I'm not happy to crawl through the process tree to dig up the leafmost process's CWD, but I am extremely happy to support OSC 7.

FYI I asked about OSC 7 handling for Alacritty, which eventually led to this issue being created in the "Terminal WG" on gitlab: https://gitlab.freedesktop.org/terminal-wg/specifications/issues/20

There's not been much movement on that ticket, but you may be interested to follow it. Especially if you guys have any opinions regarding what a "formal" specification for OSC 7 might look like.

So for the record, the thread at https://github.com/jwilm/alacritty/pull/2937 has a pretty great discussion.

Honestly, I'm pretty okay using the de-facto standard that's already in place, the OSC 7 ; <URI> ST mechanism. I'm not really sure there needs to be anything more formal than that.


Wait no I had a terrible thought. Say bash is configured to emit that, and someone runs bash in WSL. What are we supposed to do when someone tries to set the working directory to /home/zadjii? How we:

  1. tell that this is a WSL path, not a Windows path
  2. know which WSL distro this came from?

Do we need to add some property on our side that indicates "this is a WSL distro, not a Windows exe"? What happens to users who don't set that, does the duplicate tab functionality just not work (effectively silently)?

Then the next part gets harder. What happens when this command is output over SSH? The terminal can't know that the path isn't on this machine anymore, right? How does Terminal.app handle this?

Maybe this does need more specification 😨

(Off: How long is it going to be until I mix up the two of you, D Howett and D Hewitt? :))

This is a crucial missing feature.

This should be a config option for the different commands. For example, I'd like this for duplicateTab and splitPane, but not for newTab.

the escape sequence is documented in mac os terminal.app preferences as shown by this comment alacritty/alacritty#2937(comment)

On macOS, the escape sequences are actually specified in Terminal.app > Preferences... > Profiles > Tab 69387948-67d69d00-0c95-11ea-881d-375672873fb4

For the record, there's heated debate over in https://gitlab.freedesktop.org/terminal-wg/specifications/merge_requests/7 about the specification of exactly this feature. I doubt that we'll support any subset of this feature until there's an actually accepted proposal there - we'd rather not introduce another disparate implementation until there's an actual standard.

I'd recommend you to do the opposite :)

Quite a few terminals have successfully implemented OSC 7, copying from each other, resulting in happy users.

And there is somebody out there currently who thinks it isn't good enough, he thinks a formal specification is needed; comes up with a draft that is full of problems, and what I cannot understand at all, is only willing to document one of two siblings. (Note: I stopped following that thread a couple of days ago.)

Terminal-WG is not a formal authority, its documents aren't "official", aren't "standards" in any de jure way. It doesn't even have proper procedures, people with responsibilities, voting rights, whatever; no one knows what it takes to get a document "accepted" there, whatever this status means at all. It's just a collection of random unorganized folks trying to come up with something useful. Don't let those unofficial pending debates stop you from implementing a long-proven feature.

For the record, there's heated debate over in https://gitlab.freedesktop.org/terminal-wg/specifications/merge_requests/7

i commented it on the issue referenced in that pr too 😉

For anybody using Bash (from Git for Windows), a temporary workaround which has been saving me, is to store the new path every time you change dir (aliasing the cd command), then cd there when a new shell is started; this is in my _.bashrc:_

if [ "${PWD,,}" = "/c/windows/system32" ]; then
    if [ -f /tmp/pwd ]; then
        cd "$(< /tmp/pwd)"
    else
        cd ~
    fi
fi

cd() {
    command cd "$@"
    pwd > /tmp/pwd
}

I'm actually testing if I start in System32 (my terminal default start location), so that I can still type wt in the Explorer address bar and start somewhere else, but this bit is optional and should be customized if your shell starts in a different folder.

I'm not fluent enough with the PowerShell or other shells, but I guess you can do something alike.

Ctrl+T should open a new tab with the same shell and the same directory.

Not everybody agrees with that assertion.

Not everybody agrees with that assertion.

Maybe many aggree. That's how terminal app works on most Linux desktop.

Atleast it can be made as an option.

Hi, I believe it is already clear in this thread that many agree this is a useful feature, and the Windows Terminal team is also ware of this. And it is also clear that the problem here is not they don’t want to make this configurable, but they need to first figure out some technical stuff that prevents the feature from being possible.

I follow this thread to keep up to date on this feature and related discussions, but the messages like this only clutter the interface and do not help. I want to ask people to please refrain from posting messages that do little other than reiterating points that are already known.

Atleast it can be made as an option

This is what I don't get about the stubbornness. If you want to go against how most terminals behave, cool. Not even giving an option though? Where's the logic in that? Even Ctrl+Shit+D that represents duplicating a tab doesn't actually duplicate it as it sticks you in the default directory. Like you have a duplicate feature that doesn't even duplicate.

What's the "technical stuff" that prevents this feature from being possible? The code already exists. There's already a duplicate tab in Ctrl+Shift+D. It just needs to be fed the current working directory and you have the behaviour that most people are used to and that people are requesting. So I'm confused at how this has "technical stuff" blocking it.

I appreciate this type of discussion because it's quite clear that there is stubbornness involved which means this type of discussion is necessary.

Ah you're right, the original discussion is lost, because it didn't ever get linked to this thread. I'm copying the content of another post (https://github.com/microsoft/terminal/issues/2427#issuecomment-521307534) here for reference:


https://github.com/microsoft/terminal/issues/1756#issuecomment-520048598

Just chiming in;

_ (profile,working dir, environment var, etc)._

Anything about the _actual process_ on the other end is, in the general case, impossible to replicate. The connected process could be ssh.exe, whose environment variables and working directory have no bearing on the detectable environment and working directory from the terminal side. The same actually, weirdly enough, applies to WSL. It doesn't use "working directory" and it doesn't expose its environment variables to interested Windows processes in any way.

Powershell doesn't even _set_ the current working directory, so its directory can't be detected (!) either.

https://github.com/microsoft/terminal/issues/2315#issuecomment-519317472

This is one of those things that is impossible in the general case but _technically possible_. There's a lot of intricacies here, like:

powershell
cd d:\users

well, powershell isn't the first process we launched. we'd ignore the path d:\users

(in powershell)
cd d:\users

we'd ignore d:\users because powershell _doesn't actually set the current working directory_ (!!)

If your "shell" is ssh [email protected] (where we strictly define shell to be "the first process Terminal spawns on your behalf"), its working directory is always going to be C:\windows\system32 regardless of what the remote working directory is.

I'd rather not provide the feature than provide the feature with so many caveats that they'd fill a documentation page. ☹️ sorry.

https://github.com/microsoft/terminal/issues/1536#issuecomment-519107586

No, because that would likely be neigh impossible to do in a general sense. How would we duplicate an instance of vim for example? What if the foreground process has opened some sort of file for exclusive access - how could we duplicate that process?

If there's a way this can be done safely and generally I'm all ears for proposed technical solutions, but I don't think it's something that's possible, so I'm not going to be investigating it.


Even if Powershell _did_ set the working directory, we're still not positive that it's _technically_ possible on Windows to get the CWD of another process. So that's the "technical" stuff that's preventing this from working. I'd love to add this as a setting. But there are definitely still technical questions that need answering.

The solution that's being discussed in this thread involves adding support for another VT sequence to the Terminal, that the _shell_ would be able to emit to clue the Terminal in to what path it's in. This VT sequence isn't super well defined, and has edge cases that still need solving. Namely:

  • What happens when a WSL shell says "my CWD is /home/foo? There's no way for the Terminal to know that path is a WSL path, or even which distro it belongs to, so duplicating this tab would likely end up in C:\home\foo (if it exists)
  • What happens when you're connected to another machine over SSH? The Terminal won't be able to differentiate those paths from paths on your own local machine, so again, duplicating that path would be the wrong behavior
  • Every user will need to customize their prompt for various shells _manually_ to cooperate with this behavior. This isn't a blocker, but this does mean it'll be a setting that won't just work out of the box.

You're trying to duplicate the running processes? Let's look at Linux for example. If you're running SSH in your terminal and open a new tab, the new tab doesn't open an SSH connection and browse to where you are in the SSH connection. It opens up a new tab where you are on your machine. Even if the process was local and not SSH it doesn't run the process. All that's being duplicated is the tab, not the running processes.

It sounds like this is being overly complicated. You aren't duplicating VIM or SSH or any other application that's running. You're duplicating the terminal and that answers the edge cases:

  • For WSL you aren't browsing your local. If the return is /home/foo that's the location. If the location was C:\home\foo it would return /mnt/c/home/foo.
  • SSH is a process. It runs in the shell. You aren't duplicating processes. Other terminals don't. You're duplicating the tab.
  • I'm not sure what the user would have to customize, but since when is customization an issue?

There's nothing wrong with duplicating the processes. I'm sure some would love that. It's just that would be another option on top of the option to duplicate the tabs. It shouldn't be a road-block. That's extra and optional.

@PandaClone it might surprise you to learn that _some people set ssh.exe as the first thing that a profile launches, without running it from a shell_.

Like as not, there really isn’t a way for the Terminal to interrogate wsl.exe, the wrapper application that communicates with Linux processes, to get it to say what the current working directory is of the first process in its process tree.
Because it doesn’t use the windows working directory infrastructure, which stores the WD in the process environment block, just using the boring old Windows APIs _is not sufficient to tell what its working directory is._

These are technical problems that we have to solve. Otherwise, we write a feature that only works for, like, 25% of people.

If it proves to be easy: we are always willing to accept community contributions.

  • For WSL you aren't browsing your local. If the return is /home/foo that's the location. If the location was C:\home\foo it would return /mnt/c/home/foo.

Ah but see, the way this feature works as spec'd, the Terminal doesn't know who or what said "The current working directory is /home/foo". This could be cmd.exe - then yea, the user wants C:\home\foo. This could be their Ubuntu distro, or their Fedora distro, or this could be ssh connected to centos or any other possibility. All the terminal gets is a string saying "this is the working directory now".

  • I'm not sure what the user would have to customize, but since when is customization an issue?

Pretty much every shell the user runs is going to need to manually be configured to enable sending this sequence. For cmd users, they'll need to manually configure their %PROMPT% to include the sequence $e]7;$P$e. bash users will need to set it up in their PS1. PowerShell will certainly have another way to do it. The fundamental issue here though is that the shells _don't_ emit this sequence by default.

SSH isn't a shell. You can set your profile to run it first, but it's still being run from the shell. It's just your profile is being instructed to run an application immediately. That application can be anything. It doesn't have to SSH. You can instruct your profile to run another shell if you wanted to.

And even in the case that there is no terminal, how is that a problem? There are always exceptions. Defaulting to the home directory when there is no directory to go to is fine. That's not a problem where you just "oh this can't be done".

Also, this is a feature that's standard in the majority terminals with tabs. Run any Linux distro which has their own terminal flavours and they all exhibit this behaviour of opening a new tab. This isn't a feature that's going to be ground breaking magic for Windows Terminal. It's a standard feature.

Terminal doesn’t just spawn shells. It literally calls CreateProcess on the thing you provide in the profile config. SSH isn’t running in, or spawned by, a shell.

Look, we’re arguing about how possible this feature is. Can we just agree that _we want this, everyone wants it, and if we had a reasonable way forward that worked in the vast majority of the use cases users care about_ that we would have done it already? I’m trying to reduce the number of times we have to say “on that can’t be done” with some upfront planning and design work.

It’s not groundbreaking magic, it’s just complicated by the Windows and WSL process model and we think it’ll fall over in some circumstances. Nobody’s saying anything more than that.

  • For WSL you aren't browsing your local. If the return is /home/foo that's the location. If the location was C:\home\foo it would return /mnt/c/home/foo.

Ah but see, the way this feature works as spec'd, the Terminal doesn't know who or what said "The current working directory is /home/foo". This could be cmd.exe - then yea, the user wants C:\home\foo. This could be their Ubuntu distro, or their Fedora distro, or this could be ssh connected to centos or any other possibility. All the terminal gets is a string saying "this is the working directory now".

How doesn't it know who or what said the current working directory is? You're the one asking for it. You know whether it's a Command Prompt or a WSL or a PowerShell. You know where it's coming from so you know how to format the location.

  • I'm not sure what the user would have to customize, but since when is customization an issue?

Pretty much every shell the user runs is going to need to manually be configured to enable sending this sequence. For cmd users, they'll need to manually configure their %PROMPT% to include the sequence $e]7;$P$e. bash users will need to set it up in their PS1. PowerShell will certainly have another way to do it. The fundamental issue here though is that the shells _don't_ emit this sequence by default.

How is that a problem? This wouldn't be the first application to require configuration and it won't be the last. Not everything is plug and play and that's understandable. If the only way to make this work is for the user to require a configuration, how is that stopping point?

What happens when a WSL shell says "my CWD is /home/foo? There's no way for the Terminal to know that path is a WSL path, or even which distro it belongs to, so duplicating this tab would likely end up in C:\home\foo (if it exists)

I can only really speak for myself, but if I had a tab open using one profile, navigated somewhere specific, and then opened a new tab in a different profile, it would not surprise or disappoint me in the slightest if the working dir did not carry over, and the default was used instead.

I think you understand that most people asking for this feature are missing the behaviour in terminals such as those included with GNOME and macOS. Those terminals don't have to deal with the same complexities that this does, but at the same time, I don't think anyone is expecting you to try and smartly handle edge cases that simply don't exist in the software they're using as a reference point.

It sounds like a pretty hairy task even if you reduce the scope somewhat though. I hope a way can be found to include some version of this feature, as it is a nice time saver.

Could this use case be handled by #4472 in the short term? I'd personally be content with some variant of cmd.exe /c "wt.exe" new-tab -p "Ubuntu-20.04" -d $(pwd) (probably bound to a Bash macro) that would open up a new tab in the most recently focused window (which is almost certainly the window that I typed the command in).

Gonna go out on a limb and say that implementing detection for the root process's current directory is easier than implementing commandline remoting and IPC to get WT to open tabs in the same window :smile:

wow, i just came here and realize that it seems need a long journey :)

We found that in windows terminal we could split the shell windows by press shortcut alt+shift+D, but it doesn't set to same directory

I've come with a workaround: change the starting directory.

Put this function into $PROFILE (make sure to adjust $path)

function sd {
    $path = 'C:\Users\Admin\AppData\Local\Packages\Microsoft.WindowsTerminal_8wekyb3d8bbwe\LocalState\settings.json'
     ((Get-Content -path $path) -replace '"startingDirectory":.*', ("`"startingDirectory`": `"$pwd`"") -replace "\\", "\\") | Set-Content -Path $path
}

.. and you'll be able to a open new tab in the same directory almost with no hassle, just make sure to type sd before opening a new tab.

Of course, the drawback is that startingDirectory is changed every time the function is called.

It would be best to use this approach with a key re-mapper, so that when Ctrl+T is pressed the function is called automatically, and when Ctrl+F4 is pressed startingDirectory is reverted back to its original value.

Alternative solution

Inside whatever profile you are using example profile.sh or .zshrc create a ~/paths.sh file located within your $HOME directory. Paths will be updated whenever you call setCWD

This solution overrides the startingDirectory completely. Whenever you spawn a new terminal call setCWD before spawning the terminal and it will always start in the directly you last called setCWD in.

Note that I did this within .zshrc

Code:

source ~/paths.sh

if [[ $SAVED_PWD != $PWD  ]]
then
  cd $SAVED_PWD
fi

function setCWD(){
  echo export SAVED_PWD=$(pwd) > ~/paths.sh
}

You may need to create an initial file so just call setCWD.

BTW if you are using autohotkey, here's a nice and quick script to get things working

Make a file called windows-terminal.ahk and then paste this code below. Run the file and you are all set. (I recommend moving this file into the startup section so that when you restart this functionality is re-applied.

#IfWinActive, ahk_exe WindowsTerminal.exe
  ^t::
    Send, setCWD {enter}
    Send, ^t

Guys, this is very important for productivity, almost like it's above everything else. Please fix this, me and my friends will happily abandon all of the other inferior terminal emulators.

It looks like the attempt to 'standardise' OSC 7 at terminal-wg has stalled.

Is there still interest in implementing OSC 7 basically as it stands in Terminal.app?

Given that, we'd have "current host and CWD" for a given terminal, which just blats the 'process hacking' discussion; and then can decide/implement the user behaviours to make use of that information, e.g.,:

  • a "new Tab in current directory" command;
  • making "split" do this by default;
  • something magic to distinguish a WSL session from a Windows session (if they even report the same hostname? I haven't looked...);
  • a config option for "suppress OSC 7" on profiles where you _know_ it's going to send a valid-looking OSC 7 that you don't want to use, such as sshing to a remote machine that claims the same hostname as your Windows host;
  • exposing the value into something you can stick on the command line, so your ssh or wsl session _can_ appear at the same working directory as one you just duplicated.

This discussion was very focused on the first part (getting the current CWD) but I suspect the second part is the one that will need more consideration, based on the existing comments so far above. Even for that list of ideas, I'm sure a reasonable objection exists to _every one_ of them.

For those who are still intersted in this topic, I made a early PR in #7668 . This is a a friendly ping. I'd really love to hear from everyone about it.

What is the point of multiple tabs, especially fast duplication, if they don't inherit the current directory? This is such an important feature. Why not add a "hacky" workaround for now? I really don't see a problem extracting CWD from a process on Windows if it increases productivity for all the users, considering Windows itself has contained multiple such solutions for more than 20 years.

I can't understand why this feature isn't the default. I truly am boggled as to why there isn't even a way to enable this feature. This is the biggest user experience detractor I have with Terminal: from an expedience perspective I am better served by not using Terminal and instead using explorer and right clicking in the directory I want to open the shell and selecting "Open PowerShell window here" because it's faster than hitting alt+shift+d then having to cd to the right place.

Terminal adds a lot of quality of life for Windows devs. This feature would be huge jump forward for me (and I suspect others). I'll add my voice in advocating for this feature be a top priority.

I can't understand why this feature isn't the default.

I can't understand why people can't be bothered to read all the investigation that's been done in this thread, in #7668, #8214, #8166, and the other linked threads, to understand why this is actually a hard problem to solve. It turns out you can't just have a client app emit it's path - because the Terminal won't _necessarily_ know whether that's a Windows or a WSL or a cygwin path.

It's a good thing we've got a bunch of talented contributors who are hard at work finding out the right way of implementing support for this feature, without breaking backwards-compatibility for other apps. We've _just this week_ come up with a solution we're happy with, shouldn't be long before it's implemented.

Thanks @zadjii-msft !

In rereading my comment I'm realizing it comes off super accusatory and that was not my intent. I came here to say this:

Terminal adds a lot of quality of life for Windows devs. This feature would be huge jump forward for me (and I suspect others). I'll add my voice in advocating for this feature be a top priority.

And that my user experience so far has been this:

I can't understand why this feature isn't the default. I truly am boggled as to why there isn't even a way to enable this feature. This is the biggest user experience...etc

I probably should have put "as a user," at the beginning of my first paragraph.

I apologize for any offense I've given.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

Wid-Mimosa picture Wid-Mimosa  ·  3Comments

wkbrd picture wkbrd  ·  3Comments

NickITGuy picture NickITGuy  ·  3Comments

TayYuanGeng picture TayYuanGeng  ·  3Comments

zadjii-msft picture zadjii-msft  ·  3Comments