microsoft / terminal

The new Windows Terminal and the original Windows console host, all in the same place!
MIT License
95.03k stars 8.23k forks source link

Enhance shell autocompletion with a cool new user interface and shell completion protocol #3121

Open anki-code opened 4 years ago

anki-code commented 4 years ago

Hello! Thank you for the new interesting project!

I just want to let you know about 🚀 Upterm — really great proof of concept but it stopped because maintainer was gone. This terminal looks like 21st century terminal. Very sad that it isn't supported.

image

up30485947-aeaa5398-9a37-11e7-927c-769304744844

up29716319-95f9a8d8-89b3-11e7-8515-fcb236eb4454

image

image

zadjii-msft commented 4 years ago

This looks really cool, though this looks like something the shell would have to work with the terminal to achieve.

How was Upterm providing those autocomplete suggestions? Did they have their own shell they were using, or were they somehow pulling the auto-completions from bash/zsh/git somehow?

Presuming the shell provided a list of autocompletion suggestions to the terminal, drawing the UI shouldn't be that hard. Cmd would obviously never be able to support this, but powershell core sure could. I'd be curious what kind of perf there would be for something like that, with the shell emitting a list of auto-completion suggestions after some delay/on every character typed.

Doing the collapsible json thing might be quite a bit harder however :P that definitely seems like they had a custom rolled cat that worked directly with the terminal.

huoyaoyuan commented 4 years ago

I think you can get inspired by Visual Studio's C# Interactive and PowerShell ISE. PowerShell already has a mechanism to collect completions, which is used by dotnet.exe. And also, don't forget the great Language Server Protocol by Visual Studio.

n3wt0n commented 4 years ago

That would be really cool, or something like the iTerm 2 autocompletion on Mac. (cmd + ;)

image

This works for both files/folder and commands

remkop commented 4 years ago

@zadjii-msft

Cmd would obviously never be able to support this, but powershell core sure could.

Cmd could certainly achieve bash-like completion: clink enhances Cmd with tab completion, which users can customize with simple lua scripts.

While not as fancy looking as the screenshots above, it would be hugely valuable if Cmd would support this out of the box.

(More detail: see docs and pre-built completions for common tools.)

zadjii-msft commented 4 years ago

I don't disagree, projects like clink and yori are great and I love them. It's just that we really can't accept any changes to cmd.exe safely 😕 This doc covers some of the reasons why.

remkop commented 4 years ago

@zadjii-msft Thank you for the clarification. Makes sense and made me realize what a great job you and your team are doing. Keep it up! (Also thanks for pointing me to yori, I did not know about that project.)

just1a-person commented 3 years ago

Wish we had the Terminal of 2005:

image

DHowett commented 3 years ago

You know, apart from the "graphical" bit, this sounds like PowerShell. It accepts C# (procedural and object-oriented), you can write prompt plugins, you can stream files (and objects!), and it supports multiple hosting interfaces such as the PowerShell ISE (which is graphical!)

just1a-person commented 3 years ago

There is this new terminal called Warp: https://twitter.com/zachlloydtweets/status/1415343353164599299

I wish Windows Terminal was that radical and not just try to match existing Unix terminals' functionality (which it already has most of)

orcmid commented 3 years ago

There is this new terminal called Warp: https://twitter.com/zachlloydtweets/status/1415343353164599299

I wish Windows Terminal was that radical and not just try to match existing Unix terminals' functionality (which it already has most of)

I think there is a confusion of shell versus terminal and how apps are wired in. So Warp seems more integrated and purpose-built. All the questions about how one uses a terminal are about session shell use. They focus on CLI.

Since there was such a thing as stealth mode, one must presume this is to be a commercial offering. There is no hint that the code is even in the open (although there is a statement about working in public). "Stable" releases are also ratcheting pretty quickly according to the Discord. warp.dev has more. There's a nice presentation of How Warp Works. I have not found any statement about licensing or commercial use, although having forked Alacritty might be relevant, depending on how the permissive Apache License is dealt with.

just1a-person commented 3 years ago

I think the PowerShell team (or PSReadLine) and the Windows Terminal team can work together to make something like this happen.

IgnusG commented 2 years ago

There’s a plug-in for the Mac terminal that offers this functionality too

https://github.com/withfig/autocomplete

IgnusG commented 2 years ago

There is this new terminal called Warp: https://twitter.com/zachlloydtweets/status/1415343353164599299

I wish Windows Terminal was that radical and not just try to match existing Unix terminals' functionality (which it already has most of)

This looks amazing. Hope that MS Terminal can match these features at some point. The visual blocks and auto complete/history view would be awesome.

Maybe if the plug-in interface is permissive enough it could be shipped as part of plug-ins that work together with the shell.

ntindle commented 2 years ago

If I wanted to work on this, is it possible or would it be better as an extension (and thus need the extension support to be completed)?

zadjii-msft commented 2 years ago

@ntindle I suppose we wouldn't need extension support to add this to the Terminal first, if we could figure out a halfway decent way of building this into the Terminal. I guess I'd be curious to hear how you planned on implementing this. From my POV there's a couple ways we could go about this, each with upsides and drawbacks, so I'm curious what you had in mind ☺️

ntindle commented 2 years ago

Hello,

To be honest, I am wildly unfamiliar with the terminal’s code base and overall architecture. I am certain I am not the best programmer for the job, but I am interested in using the final result, even if I have to build it. That said, here we go…

My initial thoughts would be that this would have a multi stage implementation at different layers with the shell and outer terminal both needing work.

The terminal would need to be able to render “panes” (I believe pane means something specific in the context of the terminal but for now I’m just referring to a generalized UI container) on top of the shell when it receives a trigger from terminal due to time since last keypress (or elsewhere with other triggers).

The profile for each shell would use the shells respective autocomplete tooling to pull the autocomplete actions out and provide them to the terminal. This would probably be one of the simplest ways to support a wide variety of actions without having to build the auto complete engine from scratch.

This interaction would be similar to how VS Code handles language servers and auto complete in that the terminal would both decide when to show the “pane” and query the shell for the appropriate next characters.

A different approach from the completion side would be to build the equivalent of language servers that provide intelligent completions using context from the shell. I think this one would be much more powerful and popular but significantly more complex to support and implement. I believe this is how the Fig example above works.

I would greatly appreciate any advice or ideas on this, even if it is to leave it to someone with a better understanding of the terminal’s code base.

zadjii-msft commented 2 years ago

A tiny prototype is in ~dev/migrie/fhl/menu-complete-prototype~ dev/migrie/fhl/vscode-autocomplete-prototype

As a stretch related idea: It would be really cool if the ControlCore saved working directories as it saw them, and then, you could open the auto suggest menu and it's pre-populated with a stack of your recent directories for this pane, as sendInput(cd ${path})` actions.

zadjii-msft commented 1 year ago

Alrighty folks, so, it's discussion time.

I've got a prototype of this out over in #14938. That's absolutely a first-draft of this experience, and there's plenty of room for improvements.

gh-3121-for-pr

Right now, the "protocol" it is using is an OSC sequence with a blob of JSON that contains a serialization of the output of the PowerShell cmdlet TabExpansion2. This is obviously terrible. It's needlessly verbose, and it's super powershell-specific. Not only that, I suspect this doesn't include all the information we'd want to send, either.

Right now, the payload of that blob looks something like:

[
    {
        "CompletionText": "Microsoft.PowerShell.Management",
        "ListItemText": "Microsoft.PowerShell.Management",
        "ResultType": 8,
        "ToolTip": "Description: \r\nModuleType: Manifest\r\nPath: C:\\program files\\powershell\\7\\Modules\\Microsoft.PowerShell.Management\\Microsoft.PowerShell.Management.psd1"
    },
    {
        "CompletionText": "Microsoft.PowerShell.Utility",
        "ListItemText": "Microsoft.PowerShell.Utility",
        "ResultType": 8,
        "ToolTip": "Description: \r\nModuleType: Manifest\r\nPath: C:\\program files\\powershell\\7\\Modules\\Microsoft.PowerShell.Utility\\Microsoft.PowerShell.Utility.psd1"
    },
    {
        "CompletionText": "PSReadLine",
        "ListItemText": "PSReadLine",
        "ResultType": 8,
        "ToolTip": "Description: Great command line editing in the PowerShell console host\r\nModuleType: Script\r\nPath: C:\\program files\\powershell\\7\\Modules\\PSReadLine\\PSReadLine.psm1"
    }
]

Which is synthensized with a powershell command like:

function Send-Completions {
    $commandLine = ""
    $cursorIndex = 0

    [Microsoft.PowerShell.PSConsoleReadLine]::GetBufferState([ref]$commandLine, [ref]$cursorIndex)
    $completionPrefix = $commandLine

    # Get completions
    $result = "`e]633;Completions"
    if ($completionPrefix.Length -gt 0) {
        # Get and send completions
        $completions = TabExpansion2 -inputScript $completionPrefix -cursorColumn $cursorIndex
        if ($null -ne $completions.CompletionMatches) {
            $result += ";$($completions.ReplacementIndex);$($completions.ReplacementLength);$($cursorIndex);"
            $result += $completions.CompletionMatches | ConvertTo-Json -Compress
        }
    }
    $result += "`a"

    Write-Host -NoNewLine $result
}

Now, the point of discussion: How do we want to refine this sequence?

A quick /cc to @Tyriar who's driving this on the VsCode terminal side.

I may also want to cc @j4james, @wez, @christianparpart who usually have opinions on this sort of thing. I'd rather get some initial design feedback here before writing a more formal spec for terminal-wg (which has kinda just become informative, not normative anyways)

wez commented 1 year ago

Neat!

The fig.io folks may have some thoughts on this, their thing is bolting similar looking functionality on top of existing terminals through a pty and IME sandwich. https://github.com/withfig/autocomplete in case you haven't seen it. cc: @brendanfalk; not sure how much you're up for sharing/collaborating on this, but I suspect that you probably already have some OSC sequences that are similar in purpose!

May also be worth looping in say, one of the fish folks, to get their thoughts from the client side. I actually don't know how their line editor works so I don't know if they would be a prime candidate for this.

Tyriar commented 1 year ago

@wez afaik fig is based on using shell integration to extract the command args and then everything is doing using these handwritten specs. My preferred approach would be to use the shell's native asutocomplete providers (TabExpansion2/etc. for pwsh, zsh-autocomplete, bash complete, etc.), instead of re-inventing the wheel and having a parallel set of completions that comes with versioning problems.

In VSCode this is currently behind an experimental flag "terminal.integrated.shellIntegration.suggestEnabled": true, but it's kind of broken atm had some critical work that took my attention away for now.

j4james commented 1 year ago

Unless you have a boat load of shells that are lining up to use this new functionality, I'm of the opinion that we're better off just hacking something on top of the FTCS sequences (which I'm assuming is what fig is doing). That doesn't require any buy-in from the shells, other than the ability to modify the prompt, which even cmd.exe can handle.

Otherwise we're guaranteed to get people complaining about the functionality not working in their favorite shell. And we can't blame the shell if there other terminals or tools that can achieve more or less the same thing without any special shell cooperation.

Although maybe there is a middle ground, where we start with an FTCS-based approach (using some minimalist autocomplete specs bundled with the terminal), but a shell can still provide additional context and custom suggestions (with your new escape sequence) if they want to enhance that experience.

zadjii-msft commented 1 year ago

I like half agree but also half don't. I really don't love the fig-style completion specs that are external to the actual source of the command. That just sounds like a versioning nightmare to me. Plus, we'd have to also maintain a enormous list of completion data, which would suddenly stop working as soon as you encounter a previously un-spec'd command.

That being said, you're right. I don't suspect there are a lot of other shells lining up to add this / support this. I'm pretty confident there'd never be a way to support something like this for cmd.exe.

I think the middle-ground approach you described is something I'd more like to get to in the long-term. This UI is something I'm gonna start using for a whole bunch of stuff real soon, not just shell completions. In the fullness of time, I want extensions to be able to plumb their own suggestions into it. So you could have a fig extension, and then hit your figSuggestions keybinding and that would let fig give back suggestions based on the CWD and currently typed command (as powered by FTCS commands).

But I think there's room for everyone here. I think there's also space for the shell to give definitive suggestions, if it knows them. Maybe not something built-in to zsh, but something that a plugin could invoke. I really need to go research more how completions work for other shells. Do I dare start cc'ing devs on other shells? I may need to 😬

Tyriar commented 1 year ago

Something like that is what I was thinking, first class support for native shell completion engines and allowing fig specs to provide fallback completions via an extension.

Araxeus commented 1 year ago

I really need to go research more how completions work for other shells

Nushell has custom completions: https://www.nushell.sh/book/custom_completions.html

I love how they handle custom completions, that could even enable AI powered suggestions pretty easily

I'm using their recommended external completion engine https://github.com/rsteube/carapace-bin and it's working great in windows terminal (here's a nice blog post about carapace)

Screenshot of my setup ![image](https://user-images.githubusercontent.com/78568641/226058900-9d528d5a-5458-445a-802a-6061d9ec90b3.png)
Welding-Torch commented 1 year ago

IMAGE ALT TEXT

James McParlane has had success implementing a kind of suggestions system, and it is running on Windows Terminal. This video released just 2 weeks ago, so I thought I'd bring it to the attention of the developers here.

zadjii-msft commented 12 months ago

Alright, so notes on enabling the version we shipped in 1.19 are in https://github.com/microsoft/terminal/wiki/Experimental-Shell-Completion-Menu.

I'm fully intending to replace that sequence, but that's a place to start playing with it.

MattJeanes commented 12 months ago

Thank you @zadjii-msft and team it looks great!

Unfortunately I've not been able to get it working after setting up shell integration which does work, ctrl+space just appears to do nothing 😢

I've debugged it to ensure that it is actually triggering PowerShell (7.3.7) to send the completions by removing the special character markers and the setting ("experimental.enableShellCompletion": true) is definitely on at the root of the config file.

Windows Terminal Preview version is 1.19.2682.0

Not sure where the best place to ask for help with that is, in this issue, a new issue or a discussion - cheers

zadjii-msft commented 12 months ago

WELP We're doing a bug bash with the team right now and iT wOrKs On My MaChInE but it doesn't on @carlos-zamora's and we're trying to debug as we speak

zadjii-msft commented 12 months ago

omfg I typo'd the wiki.

It's experimental.enableShellCompletionMenu

MattJeanes commented 12 months ago

Thanks it works now!! 😄

image

lost22git commented 12 months ago

Screenshot 2023-09-27 062555

and

Screenshot 2023-09-27 062644

Looks like the second one is more efficient

sanket-bhalerao commented 12 months ago

i still see the old prompt image

lost22git commented 12 months ago

i still see the old prompt image

maybe you forgot to restart wtp?

christianparpart commented 12 months ago

Hi,

I know I am very late (private life and such), but I indeed wanted to drop some comments, because I think we should avoid re-inventing the wheel for every MxN component in the huge matrix of terminal emulators on the one dimension and shell programs / CLI apps on the other dimension.

What I imagine is some kind of at least shell-agnostic auto-complete system (I recently talked to some ex-Fig and other TE devs about it) that a shell simply needs to hook into the protocol and then can use "One common shared code completion definition database". I learned that this is what fix is already doing, but they had issues when it came to tools with conflicting names. I suggested triggers (like Github Actions' CI if: statement).

Now. What could the terminal offer here? Well, Fig does provide its own intermediate layer (horrorble performance impact) that also works by interchanging JSON payload via OSC (similar to you as of right now). I'd actually probably do it more or less the same. The shell now however should probably invent some VT sequences to make popups work. That may indeed be an OSC (in order to allow string parameters), such a popup should be flexible enough to allow the user to choose an item from a list of items, and have each item in that list annotated (probably in markdown syntax, as it's most well known, little to no added complexity, easy to understand by any future completion contributor). That popup would then reply back to the TE app with the selected item. There a CSI seq could suffice (as returning an index to the selected choice could be enough), but having OSC might work too (to make request and response somewhat similar).

I soon wanted to design a VT extension draft for specifying general tooltips, that shells (including pwsh) could make use of to display LSP-like tooltips on hover events as well. So there is plenty of room for improvement for the TE/TUI/CLI space. :-)

How do we make this something that pwsh, bash, zsh, fish, nu... anyone really, could emit easily?

Basing the work that Fig did for an at least initial central completion definition database. I think that should work. The specific shells that want to make use of these, simply implement their own integration and read those YAML/JSON completion definitions and evaluate upon them. Dynamic context might be possibly given too (should in fact be supported), and initially I thought, giving these in basic sh/bash syntax should suffice. But I completely forgot about pwsh (and its primary platform: Win) being entirely different. 🤔

Similarly, the same menu could be used by something like vim. Would it be possible there?

This is basically what I also proposed above with a hopefully well designed VT sequence extension. I didn't think about vim, but rather about shell programs here.

An OSC seems a little silly for this - would a DCS make more sense? an APC (ew)? What's the actual wire format look like?

Looking at all those VT sequence groups (ESC, CSI, DCS, OSC, PM). I at first would have chosen DCS, because it makes me think that D (device) is the TE. But IIRC there were terminals that didn't parse DCS correctly. That might only apply to somewhat oldish/rubbish TEs though. Not sure that should be relevant to anyone wanted to implement such a protocol extension. The big diff probably is, that OSC's by habbit seem to always start with a number as identifier, for DCS there is no such grouping (as of yet). Surely, @j4james knows better. :)

In the end, @zadjii-msft, whatever you come up with. I'd be more than happy if it will be something that is implementable by other TEs as well, not just on Windows, but ideally also on non-Windows platforms, and not just for pwsh, but ideally also for other shell programs or even apps.

hanhwi commented 12 months ago

I just tried the profile and settings in the wiki. It seems that the terminal cannot process the character sequences for command suggestions. Which version should I use for this feature? I am currently on v 1.19.2682.0

image

zadjii-msft commented 12 months ago
  1. Op, I should probably make a note about ctrl+space, since lots of folks already use that for MenuComplete. You may want to pick different keys
  2. welp I forgot that Windows PowerShell (5.x) doesn't support `e as an escape character. I'll need to edit the sample to use the whole [char]0x1b thing for back-compat.
  3. @christianparpart Oh don't you worry, I think I've got almost all the same thoughts as you in this space. Sometime over the next few months I wanna take what we have here, mostly throw it out, and propose a different version to terminal-wg[^1]. Shell-agnostic, client-agnostic, and terminal-agnostic.

[^1]: terminal-wg is of course, mostly dead, but it is still a place to go. I'm not sure that consensus building is something that'll happen there. I still think there's room for it to be informative, but not normative.

sanket-bhalerao commented 12 months ago

i still see the old prompt image

maybe you forgot to restart wtp?

i have restarted the terminal several times, but still see the same result.

zadjii-msft commented 12 months ago

@sanket-bhalerao mind filing a new issue, with your settings.json file and your PowerShell profile? We can debug over there, and report findings back to this thread ☺️

j4james commented 12 months ago

But IIRC there were terminals that didn't parse DCS correctly.

@christianparpart The Windows 10 console is one such terminal. The issue was fixed years ago, but I don't think Windows 10 gets updates anymore. But it's not a problem as long as apps use some form of feature detection before using the sequence. I wouldn't recommend apps use any string sequence without feature detection.

The big diff probably is, that OSC's by habbit seem to always start with a number as identifier, for DCS there is no such grouping (as of yet).

The DCS intermediate-final characters are the equivalent of the OSC number. You can think of it as a self terminating base-16 number, so you have something like 65 times more range for a 4 byte value.

sanket-bhalerao commented 11 months ago

@sanket-bhalerao mind filing a new issue, with your settings.json file and your PowerShell profile? We can debug over there, and report findings back to this thread ☺️

@zadjii-msft I have raised a bug: https://github.com/microsoft/terminal/issues/16053 UPDATE: I added incorrect configs at incorrect places. after @zadjii-msft pointed it out and I corrected the configs the feature is working as expected :)

rsteube commented 11 months ago

fyi Powershell supports colored completion using escape codes:

default

terminal

jerkovicl commented 11 months ago

@rsteube how did you configure this?

rsteube commented 11 months ago

@jerkovicl Windows Terminal according to the wiki, the completions are custom. Shouldn't normally be an issue though, i'm using the powershell completions a bit differently.

jerkovicl commented 11 months ago

@rsteube yeah i have meant the color part and the command description

rsteube commented 11 months ago

I'm adding it to the ListItemText instead of the ToolTip.

using namespace System.Management.Automation
using namespace System.Management.Automation.Language
Function _git_completer {
    [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingInvokeExpression", "", Scope="Function", Target="*")]
    param($wordToComplete, $commandAst, $cursorPosition)
    $commandElements = $commandAst.CommandElements

    # double quoted value works but seems single quoted needs some fixing (e.g. "example 'acti" -> "example acti")
    $elems = @()
    foreach ($_ in $commandElements) {
      if ($_.Extent.StartOffset -gt $cursorPosition) {
          break
      }
      $t = $_.Extent.Text
      if ($_.Extent.EndOffset -gt $cursorPosition) {
          $t = $t.Substring(0, $_.Extent.Text.get_Length() - ($_.Extent.EndOffset - $cursorPosition))
      }

      if ($t.Substring(0,1) -eq "'"){
        $t = $t.Substring(1)
      }
      if ($t.get_Length() -gt 0 -and $t.Substring($t.get_Length()-1) -eq "'"){
        $t = $t.Substring(0,$t.get_Length()-1)
      }
      if ($t.get_Length() -eq 0){
        $t = '""'
      }
      $elems += $t.replace('`,', ',') # quick fix
    }

    $completions = @(
      if (!$wordToComplete) {
        carapace git powershell $($elems| ForEach-Object {$_}) '' | ConvertFrom-Json | ForEach-Object { [CompletionResult]::new($_.CompletionText, $_.ListItemText.replace('`e[', "`e["), [CompletionResultType]::ParameterValue, $_.ToolTip) }
      } else {
        carapace git powershell $($elems| ForEach-Object {$_}) | ConvertFrom-Json | ForEach-Object { [CompletionResult]::new($_.CompletionText, $_.ListItemText.replace('`e[', "`e["), [CompletionResultType]::ParameterValue, $_.ToolTip) }
      }
    )

    if ($completions.count -eq 0) {
      return "" # prevent default file completion
    }

    $completions
}
Register-ArgumentCompleter -Native -CommandName 'git' -ScriptBlock (Get-Item "Function:_git_completer").ScriptBlock
jerkovicl commented 11 months ago

@rsteube oh cool, thx for snippet:)

rsteube commented 11 months ago

It's on scoop and winget if you want to try it yourself. Just add this to your profile and it should work:

# ~/.config/powershell/Microsoft.PowerShell_profile.ps1
Set-PSReadLineOption -Colors @{ "Selection" = "`e[7m" }
Set-PSReadlineKeyHandler -Key Tab -Function MenuComplete
carapace _carapace | Out-String | Invoke-Expression
jerkovicl commented 11 months ago

@rsteube thx, i installed and set it all up, it works:)

Jaykul commented 9 months ago

Is there any way to have the completion menu support typing to narrow down the list?

Tyriar commented 9 months ago

FYI thanks to some contributions from @cpendery you can once again enable suggest in VS Code's terminal ("terminal.integrated.shellIntegration.suggestEnabled": true) starting from the next insiders build which should ship sometime in the next few days:

Recording 2023-12-07 at 06 28 43

It's still rough around the edges and not close to feature complete, but I believe we fixed the show stopper bug that bricks the terminal 😅. Here's the issue tracking the feature https://github.com/microsoft/vscode/issues/154662