PowerShell / PSReadLine

A bash inspired readline implementation for PowerShell
BSD 2-Clause "Simplified" License
3.74k stars 296 forks source link

[FeatureRequest] Support color theming for all AST element types #982

Open JustinGrote opened 5 years ago

JustinGrote commented 5 years ago

This is a continuation of https://github.com/PowerShell/PSReadLine/issues/981

There are several language elements in Powershell that aren't covered by the current syntax highlighter. Since PSReadline uses AST, the list of possible elements could be dynamically queried from AST and added as color options to the color settings hashtable. This would require a little reworking of the current settings method since the options are hard-coded today.

This would enable accurate representation and reproduction to match some editor theme styles. For instance, in the PSES TM syntax, the function keyword can be highlighted differently (and is by default in VSCode Dark+ Theme) than other keywords, but not so in PSReadline.

For example, the function keyword can be highlighted as a separate element using the PSES Textmate grammar, however PSReadline sees it just as an operator.

VSCode Editor

image

PSReadline

image

Example of querying possible AST types (I'm sure there's a way better method to call somewhere in C#)

[AppDomain]::CurrentDomain.GetAssemblies() |  
    Foreach-Object { $_.GetTypes() } | 
    where fullname -match 'System.Management.Automation.Language.+Ast$' | 
    % name | 
    sort

Example Result

https://gist.github.com/JustinGrote/901d9db90b69bab8f104c851c80e8658

lzybkr commented 5 years ago

Coloring is token based, not tree based (an Ast is a tree), so you're really asking to color based on TokenKind.

I can't say I really like the idea (too many colors can be confusing), but it would be pretty easy to support. Today you customize colors with:

Set-PSReadLineOption -Colors @{
    "Command" = "#8181f7"
}

We could extend this without breaking anything by allowing a TokenKind as a key, e.g.

using namespace System.Management.Automation.Language
Set-PSReadLineOption -Colors @{
    ([TokenKind]::Function) = "#8181f7"
}
vexx32 commented 5 years ago

Couldn't you simply opt to internally cast all the keys to tokenkind to see which they'd be applicable to? Would bypass the need for the awkward syntax.

lzybkr commented 5 years ago

You could and I considered that, but there is the small risk of collisions if PowerShell were to add a new token kind.

Note that there are currently 5 allowed values that also happen to be a valid TokenKind:

That leaves the following as "at risk" for future changes to PowerShell:

While the risk is small, Default and Error both seem like reasonable candidates for actual tokens in PowerShell.

vexx32 commented 5 years ago

Maybe just support a string syntax as well to cut down on the awkward symbology, like a key named 'Token:Command' is considered to be [TokenKind]::Command

JustinGrote commented 5 years ago

@vexx32's option makes sense to me to preserve backward compatibility while allowing for flexible direct casting to the TokenKind enum and keeping the syntax simple, however I don't have a problem either way if you want to preserve strict typing there.