-
Notifications
You must be signed in to change notification settings - Fork 8.3k
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
Discussion: Find a way to make OSC7
work
#8214
Comments
I don't know if I'm missing something, but this really doesn't seem like it should be that complicated to me. If the path looks something like If the profile command line is something like And I'm assuming cygwin could be handled in the same way. Either there's an algorithm we can use to work out the correct path ourselves, or we launch an instance of If we're concerned about performance, we could always do something like translating just the root path, and then reuse that translation for future paths sharing the same root. But in most scenarios where the path is needed, the overhead probably wouldn't even been noticed. Yes this is going to require a lot of special case code for every variant of shell we want to support, and it's not going to be pretty. But I'd much rather have that mess isolated in the Terminal instead of every application and shell script having to deal with it. And remember this problem is specific to Windows Terminal. Once wsl supports Linux GUI applications, there are assumedly going to be plenty of other terminal apps running on wsl that won't have this problem. So if you're expecting applications to treat us differently, it's not good enough to detect that they're in a wsl instance - they need to tell that they're running in Windows Terminal, which is not something we've wanted to encourage. And before anyone starts bringing up edge cases where this won't work, ask yourself whether that is a realistic scenario that users would expect to work? And there is always still the option of a custom sequence to handle special cases, or requiring the path be in a particular format. The important thing is that the out-of-the-box solution handles the 99% of cases where the user is just launching a regular shell, and having the terminal recognise a standard |
The edge case that I immediately think of is running WSL from a "Command Prompt" profile. If you enter any one of these "containered" environments from a profile that doesn't match, then immediately any logic that uses the profile to do the translation isn't going to work. If that's an acceptable outcome, then yea, this is easy to do. Heck, we could just slap a I'm still holding out hope that there's a way to do it without that, but the hope is fading fast.
You're absolutely right about that. I'll make sure to keep that in mind, that being in WSL does not guarantee that the path must be Windows-friendly, only that being in WT does. And I'm sure as heck not going to ship anything that forces developers to check if they're in WT. |
Is this really that common though? And what would a user expect to happen in this scenario if they opened a "duplicate" tab? Are they expecting it to open a cmd shell starting in the directory they were in in the WSL shell? Even if we did know how to map that, it doesn't seem like a reasonable expectation to me. Unless the path happened to be |
In #7668 I choose to move the burden to shells, which make things easier on the terminal side. And yes it can properly handle “running WSL from a "Command Prompt" profile”, since it’s profile-agnostic. James is leaning towards keeping the ugliness inside terminal, in a case-by-case fashion to handle the path transformation in WSL, Cygwin, etc. One of the reasons why I like the shell approach, is that I feel the ugliness is relatively smaller than the terminal approach. I mean it’s bash/zsh, right? People have already been putting everything in it since those shells were born. The other reason is that during the discussion in #7668 I found that the path transformation isn’t just simple string replacement. To transform the path competently, we need wslpath, which is inside the WSL environment. This just adds even more ugliness in the terminal approach. Now that I think of it, neither of them is a perfect solution. The tricky part of is the nature of WSL. It’s a complete Linux environment yet has the ability to interact with the Windows world. It’s so special that none of the VT sequences was ready to handle it. In conclusion, WSL is, after all, a Microsoft product. If we choose the terminal approach, I think it’s fair to handle it in WT, to make life easier for people. I’m not feeling the same for Cygwin or other kinds of profiles, though. |
No, it's potentially used in other applications too. For example, egmontkob added an option to Midnight Commander that would make it report it's current directory via the |
Fully agree. We should accept what apps generate and attempt to determine, to the best of our knowledge, how to interpret that. If this means that our autogenerated WSL distribution profiles act better[1] than "User ran wsl.exe from cmd and now something acts silly", I think that I'm willing to accept it. 1: (assuming we do some profile magic to make them "aware" of their namespace prefix) |
Great! I think we have an agreement that the terminal approach is the correct way to handle OSC 7. Still I’d like to make ConEmu’s OSC 9;9 to work. This sequence needs integration from shell at the time it was born. And it’s clearly Windows-first. I’d like to think it a pioneer on our way towards a more complete OSC 7 solution, which presumably takes longer time. I want people to have a working even though not perfect solution. I’ll copy #7668 to another PR that uses OSC 9;9. Together with all the shell scripts, people can enjoy the CWD feature if they are willing to tweak the shells. Sounds good? |
I think we're all in agreement here. Glad this discussion was able to bear fruit after all! I'll close this thread now that we have a path forward with `OSC7. Thanks everyone! |
<!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? --> ## Summary of the Pull Request This PR implement the OSC 9;9 |Sequence|Descriptoin| | :------------- | :----------: | |ESC ] 9 ; 9 ; “cwd” ST | Inform ConEmu about shell current working directory.| <!-- Other than the issue solved, is this relevant to any other issues/existing PRs? --> ## References #8214 <!-- Please review the items on the PR checklist before submitting--> ## PR Checklist * [X] Closes #8166 * [X] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA * [ ] Tests added/passed * [ ] Documentation updated. If checked, please file a pull request on [our docs repo](https://github.com/MicrosoftDocs/terminal) and link it here: #xxx * [ ] Schema updated. * [ ] I've discussed this with core contributors already. If not checked, I'm ready to accept this work might be rejected in favor of a different grand plan. Issue number where discussion took place: #xxx <!-- Provide a more detailed description of the PR, other things fixed or any additional comments/features here --> ## Detailed Description of the Pull Request / Additional comments <!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well --> ## Validation Steps Performed
<!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? --> ## Summary of the Pull Request This PR implement the OSC 9;9 |Sequence|Descriptoin| | :------------- | :----------: | |ESC ] 9 ; 9 ; “cwd” ST | Inform ConEmu about shell current working directory.| <!-- Other than the issue solved, is this relevant to any other issues/existing PRs? --> ## References microsoft#8214 <!-- Please review the items on the PR checklist before submitting--> ## PR Checklist * [X] Closes microsoft#8166 * [X] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA * [ ] Tests added/passed * [ ] Documentation updated. If checked, please file a pull request on [our docs repo](https://github.com/MicrosoftDocs/terminal) and link it here: #xxx * [ ] Schema updated. * [ ] I've discussed this with core contributors already. If not checked, I'm ready to accept this work might be rejected in favor of a different grand plan. Issue number where discussion took place: #xxx <!-- Provide a more detailed description of the PR, other things fixed or any additional comments/features here --> ## Detailed Description of the Pull Request / Additional comments <!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well --> ## Validation Steps Performed
I think we all agree that we want a sequence that'll work for a client app to set the current working directory of the Terminal. How exactly that's enabled is still up for discussion. There's already existing user scripts, tools, etc that are using
OSC7
to set the CWD of the Terminal. However, those who are using it are using it to set the path relative to the "container" - e.g. in WSL, the "container root" is/
, but as far as the OS is concerned, that path is actually\\wsl$\DistroName\
.I'm aware we've already got #3158 tracking adding support for
OSC7
, but there's a ton of folks that are all following that discussion as the "enable opening a new tab with the same directory", and I'd rather keep this discussion more focused.(That being said - the rest of this post is basically my verbatim notes, turned into a thread. I've got some though experiments below for what we could do here, but none of them are particularly good.)
For the completeness of discussion, let's also refer to
OSC 9;9
- the ConEmu sequence for setting the working directoryfile://
URI when emitted as part ofOSC 8
hyperlinksstartingDirectory
as a WSL path, not just as a Windows path.Let's imagine emitting this sequence in the following scenarios:
how we'd want to convert the path
hostname
toprevent these sequences from being accepted. It's up to the user to make
sure that the machine they're ssh'd to doesn't have the same
hostname
.tmux
orscreen
, or any other ort of multiplexer that might need to get in between the client app and the terminal emulatorOSC7
Conclusions(I originally wrote this for #7668 (comment))
Basically, we've got two simultaneously incompatible issues. Either we:
literally use whatever directory they emit (assuming the hostname matches)
file://$hostname/$PWD
in WSL, cygwin, will get unexpected behavior. We'll try and treat$PWD
as a path to a Windows directory - which might be a path that exists. When they try to open a new tab with that same directory, it'll open not in the distro the sequence originated in, but in the Windows filesystem. Not great!OSC7
into the correct Windows path. WSL clients won't need to change any of the scripts they were already using for this to "just work".wsl.exe
to the distro within WSL that's being used. Similarly, we can't use the profile to do this, because the user might be using WSL w/in their "Command Prompt" profile (for example).<distroName>
, when I emit paths, handle them specially". If we did introduce such a new custom sequence, then we're not really faithfully implementingOSC7
now are we? For clients to work as they did before, they'd still need to add emitting this custom sequenceI think at the end of the day, I agree with @j4james. If we implement
OSC7
as requiring a Windows-style path, then that'll necessitate that client applications will need to be modified to work right on Windows, and I hate that idea.OSC9;9
- the ConEmu solutionThis one doesn't seem that bad. Since it's a windows-first sequence, it doesn't need to know anything else about who's emitting the path. We can always assume it has been emitted as a Windows path. On the surface, this seems to work great, save for one scenario - ssh. This sequence doesn't accept any sort of
hostname
, it only takes the path. So if you weressh
'd into another machine, and that one emitted aOSC9;9
, then there's no way of determining that sequence wasn't intended for the current machine.I think I'm okay with us implementing this as-is for the time being though. It's not a perfect sequence, but it's good enough, and doesn't come with the compat baggage that
OSC7
does. It can certainly be supported with the caveat "This won't work in an ssh session, or in any scenario where it's emitted by a remote connection. It will always be treated as a path on the local machine".Creating a custom sequence
While noodling on all this, I considered, "what would we want for a perfect set working directory sequence"? Why isn't OSC7 good enough for us? I think my analysis is that the thing emitting the sequence shouldn't need to know if it's inside a container, inside a WSL, running in an ssh session. The client application should be able to emit the same sequence regardless, and the Terminal should be able to just do the right thing.
The WSL path -> Windows path thing is tricky, but could we work around it somehow?
I'm thinking it might be useful to introduce some new "path metadata" sequence, that controls how paths emitted by
OSC7
are handled. While this wouldn't strictly be in-line with the rest of the OSC7 spec, it would allow these sequences to be used otherwise unmodified on Windows, and might help make emitting these sequences in containers more useful. I'm thinking something likeIdea 1 - K/V Pairs used by the Terminal to reverse-engineer the path
Which lets the client specify a set of key, value pairs that should be used by the terminal when handling paths emitted by the client, and that's it.
This sequence would have to be emitted on startup of something like WSL, docker, or ssh, and they'll be responsible for setting these values for the terminal[1]. So WSL would emit something like:
The Terminal could then use these pieces of information to make smarter decisions about paths.
[1]: Obviously, this could be emitted during login in
.profile
or something else, as a stopgap while we wait for WSL to emit something like this. I'd think users would want to use it sooner than later, and if there's a way for the shell to determine it's running in WSL, then fine, I won't stop users from writing new code that'll work both now and in the future.Idea 1 conclusion
This is a terrible idea, because it requires the terminal emulator to be aware of any and all of these possible scenarios. Every terminal emulator out there would need to be manually updated to be able to handle WSL paths, cygwin paths, docker paths. If any other container-like environment was created, then the terminal emulator would also need to be updated to have other logic for that case as well.
Also, how does nesting these things work? How would the logic of
wsl
->cmd
->cygwin work?Idea 2 - Specify a commandline for path translation
The thing that's creating the nesting pushes/sets a path transform onto the Terminal. So
wsl.exe
would sayThen, when the client emits a path, we'd use the provided commandline to translate the path for us. We'll run the given commandline, and if the exit code is non-zero, we'll use the output of that commandline as the real path.
We'd need both a transform for outbound paths (paths emitted by the client) and inbound paths (paths created by the Terminal, e.g. the drag-drop path situation).
Idea 2 conclusion
Obviously this is a terrible idea. All you have to do is have your script emit
^[]9001;2;malicious.exe^[\
and now you've got a malicious exe running on every prompt, with the path that's being used by the user.Also, how would this work with ssh? we'd filter the paths out by hostname, but what if you ssh'd to a Windows machine, then ran wsl in there? That WSL would inform the terminal to treat paths like they were WSL paths. However, WSL is running on the remote machine, not the local one! The terminal can't use that
wslpath.exe
Idea 3 - Static path translation mapping
Static path translation table. The containerizer (wsl, cygwin, docker) sets up a list of paths and what they should be mapped to. E.g.
The above example would set up two pairs of mappings (
/mnt/c
->C:/
), and(
/
->\\wsl$\Ubuntu\
). When the terminal emulator receives a path fromOSC7
orOSC8
,then it'll look through the table and find the mapping with the longest prefix
match for the given path.
So, if someone emits
^[]7;file://localhost/mnt/c/foo^[\
, both/
and/mnt/c
will match, but we'll take
/mnt/c
since that's the longer match. We'll thensubstitute that prefix with whatever it's mapped to, so
/mnt/c/foo
becomesc:/foo
We'll do the reverse when someone drag/drops a path onto the Terminal
wsl -d Ubuntu
, thenpwsh.exe
, thenwsl -d Debian
. Nowwe're in Debian, and we want the paths to be translated to
\\wsl$\Debian\
,not
\\wsl$\Ubuntu\
. That's fine, when WSL enters the Debian instance,it'll emit the sequence again, re-mapping
/
to the new root. However, ifwe exit Debian, now the
pwsh.exe
would need to reconfigure the rootsitself.
wsl -d Ubuntu
thenpwsh
. Doespwsh
then set up the mappings itself?itself? That's almost never the case with other sequences. (consider SGR
sequences. If you care, then you'll assume the child polluted the state, and
reset.) People who care about the paths being remapped should assume that
any child subprocess might change them.
prompt), the shell would need to set up the mappings again. This is
basically the same as just emitting a Windows path in OSC7 to begin
with! Like, the only benefit we get is that child processes would
inherit your mapping by default, but they could always overwrite it.
c:\foo\bar
, then will we generate/mnt/c/foo\bar
or/mnt/c/foo/bar
?\
vs/
.=
a valid path character in either *nix or NTFS? If it is, thenwe'll need something else as a delimiter that's not a path character
Idea 3 conclusion
IMO this is no worse than asking people to change their scripts to emit aWindows path in OSC7. If they already have to change their scripts, then adding
this mapping script once in their profile or wherever will make it just work for
all the tools they're using, not just the ones they can change
Nevermind. This is just about as bad as just forcing people to use Windows paths in the prompt in the first place.
Idea 4 - stick the metadata right in the OSC7 sequence
Could we add additional parameters to OSC7, after the path, that a terminal emulator could use to say "Ah yes, this path might be inside a container, lets handle it specially"? This kinda admits that we won't be able to add any other sequence that'll make OSC7 work on its own without modification. If the takeaway from idea 3 was "no matter what we do, the shell needs to reconfigure the path mapping whenever a child exits", then I'm starting to worry that could be extrapolated to any design we make.
Idea 4 Conclusion
So I guess, if we're going to be asking people to modify their existing tools that use
OSC7
, then why not just use OSC7 as-is, with the caveat "If this is running on Windows, it's gotta emit the Windows-relative path"Reference
The following post by @TBBle is incredibly useful
#7668 (comment)
Anyway, how to generate the URL is not the main issue for Windows Terminal, it's how to parse it. Ideally, we want to receive URLs that are already in the right format to just pass through
urlmon
or similar, and get back a UNC or filesystem path.To get everything interoperating well, we need to handle (off hand):
file://localhost/$CWD
, because CMD only knows DOS paths.$executionContext.SessionState.Path.CurrentLocation
knows if it's on a 'Drive' or not, so this can easily do different things for either type of path.cygpath --mixed ${PWD}
, and then it looks just like CMD, above.cd
to UNC paths in the cygwin virtual filesystem, and in this case, the local PWD is the UNC path. Helpfully,cygpath --mixed ${PWD}
works for all these cases anyway.--mixed
instead of--windows
so the slashes are already correct, so the OSC 7 URL can be literallyfile://$(hostname)/$(cygpath --mixed $PWD)
and it seems that'll always work./mnt/X/...
whereX
is a drive-letter should map through to a DOS path for that Drive.//wsl$/${WSL_DISTRO_NAME}/${CWD}
.cygpath
now, to hide all the above.file://
URL. That might actually be desirable, if I am SSH'd to a machine on my LAN, and then launch a PowerShell tab and it does actually go into the same directory, via UNC. However, that'd be an unusual CIFs layout (NFS 3 worked that way though...) so I can't see this as being a common use-case.Happily, it seems
${WSL_DISTRO_NAME}
exists, and I assume it's inserted by the wsl shell launcher, so it is possible to generate the full correctfile://
URL in one's PS1 env-var. This even means you can key off the presence of${WSL_DISTRO_NAME}
(or${WSL_INTEROP}
perhaps) to share the same OSC 7 generation code with out-of-WSL environments.One possible approach to the above: is that if everyone generating OSC 7 commands for Windows paths agrees to only generate a modified-'legacy file:// URL' format, i.e.
file://<gethostbyname()>///<UNC hostname>/<UNC path>
orfile://<gethostbyname()>/<DOS Path>
, then WT could recognise when<gethostbyname()>
matches the current$COMPUTERNAME
, and replace it withlocalhost
(making it a correct "legacy" file:// URL) before passing it through to the URL handler to get the actual working directory.Then any other hostname, except 'localhost' and 'empty string', could be treated as 'remote' and ignored. For 'localhost' and 'empty string' hosts, we'll just trust the user isn't generating those from a remote host. There's nothing else we can do there.
This seems the closest in-spirit to the Freedesktop file:// URL specification, and means that URLs generated for OSC 7 on Windows will be semantically-similar to URLs generated for OSC 7 on UNIX-type systems, and can be parsed the same way.
Other tabs I had open:
I'll keep thinking about this, but let's use this as a place to continue thinking about how we might do right by the users here.
The text was updated successfully, but these errors were encountered: