Search code examples
powershellterminalfontsconsolewindows-subsystem-for-linux

Change font type and size programmatically on the console


Of course I can go into settings and change fonts and that question has been answered with many great answers elsewhere. This is quite a different question (or at least, I have not found an answer yet). There is a small discussion on this (just for PowerShell though) 4 years and 7 months ago, but that seemed to be a dead end (and was before the existence of WSL and Windows Terminal of course).

If I am in a console I would like to be able to type a command to change the font of the console that I'm in (whether by registry or json settings in Windows Terminal etc)?

e.g. Resize-Console Consolas 14 inside the console would immediately change the console to that font size, without having to go into the settings panel etc.

I would be very happy if a solution only worked on Windows Terminal, as that is clearly the one-size-fits-all future that Microsoft are focusing on for consoles on Windows, and it has a json settings structure that is probably more easily modified than other consoles.


Solution

  • As far as I know, the font settings are only available through the settings.json at the moment. Usually I'd recommend using jq to edit the json, but settings.json includes comments, which make it "not really json" according to jq.

    (Aside - This isn't really a jq issue. Mixing code (comments) inside a data structure does make it tough to process. I think you'd really have to shift from processing the data structure to processing the AST. In my experience, most libraries won't/can't retain comments inside of data, no matter what the data type.)

    If you are okay stripping out the comments (I'm not - They are very useful), then you could do this with a fairly straightforward simple jq query/set.

    But if we want to leave the comments in, we need to treat the settings.json as simply "text", and go old-school with something like sed. Note that this example assumes that you have added "fontFace" and "fontSize" inside your profiles.defaults`. If you have or want it set on a per-profile basis, you'll need to adjust the regex accordingly.

    Here's my section, abbreviated:

    {
        "$schema": "https://aka.ms/terminal-profiles-schema",
    
    ...
    
        // A profile specifies a command to execute paired with information about how it should look and feel.
        // Each one of them will appear in the 'New Tab' dropdown,
        //   and can be invoked from the commandline with `wt.exe -p xxx`
        // To learn more about profiles, visit https://aka.ms/terminal-profile-settings
        "profiles":
        {
            "defaults":
            {
                // Put settings here that you want to apply to all profiles.
    
                // From Nerd Fonts
                // https://github.com/ryanoasis/nerd-fonts
                "fontFace": "CaskaydiaCove NF",
                //"fontFace": "CodeNewRoman NF",
                //"fontFace": "SauceCodePro NF",
                //"fontFace": "UbuntuMono NF",
                //"fontFace": "Consolas",
                "fontSize": 13,
                "cursorShape": "filledBox"
            },
    ...
    

    With that in mind, the following sed invocations work for me to change the fontFace and fontSize:

    winhome=$(powershell.exe -c 'Write-Host -NoNewLine  $env:userprofile' | xargs -0 wslpath)
    cd ${winhome}/AppData/Local/Packages/Microsoft.WindowsTerminal_8wekyb3d8bbwe/LocalState
    sed -i '/"defaults"/,/fontFace/s/^\(.*fontFace": \).*/\1"Consolas",/' settings.json
    sed -i '/"defaults"/,/fontSize/s/\([^/]*fontSize": \)[0-9]*/\115/' settings.json
    

    The first two lines aren't strictly necessary if you wanted to hardcode to your user path, of course.

    A couple of other caveats for these sed scripts:

    • The "real" fontFace line must be the first uncommented one. This script will change the first one it comes across, regardless of whether it is commented or not. Same with fontSize, of course.

    • Adjust the script to not add a comma needed.