How to? Use oh-my-posh with TCC

Jun 2, 2008
40
0
Denmark
I have used oh-my-posh with powershell and bash for some time now and I quite like it. However, oh-my-posh did not work with TCC...

Well, it does now - mostly...

My initial inspiration came from this posting. Here I found the overall framework needed to get an oh-my-posh prompt converted to something TCC can use. As in the posting I refer to, I use a library function to create the prompt string:

Code:
BuildPrompt {
   :: Do not disturb
   @echo off
   setlocal

   :: Save parameters
   set theme=%1
   set appendspace=%2

   ;; The TCC (and cmd.exe) PROMPT command does not allow for multiple lines in a prompt string.
   :: So we collect the output from oh-my-posh in an array.
   set LINESNUM=10
   setarray /f promptlines[ %LINESNUM ]
   echo %@execarray[ promptlines, oh-my-posh.exe --shell universal --config %theme ] >& nul

   :: For some reason the first line is empty. Se we need a mechanism to skip empty lines
   set skiplines=1
 
   :: Process the lines to build a prompt string for TCC
   do index = 0 to %LINESNUM
      iff %skiplines then
         iff "%promptlines[ %index ]" == "" then
            :: Discard empty line(s)
            iterate
         else
            :: No more skipping lines
            set skiplines=0
            :: Add first line to prompt string
            set promptstr=%promptlines[ %index ]
         endiff
      else
         iff "%promptlines[ %index ]" == "" then
            :: Exit loop when we encounter the first empty line
            leave
         endiff
         :: Append the next line to the prompt string separated by a newline $ sequence ($_)
         set promptstr=%promptstr%$_%promptlines[ %index ]
      endiff
   enddo

   :: It seems that arrays are not destroyed automatically by endlocal so a bit of explicit cleanup
   :: is needed.
   unsetarray promptlines

   iff defined appendspace then
      :: Present the result to the world with an extra trailing space
      echo %promptstr%$s
   else
      :: Present the result to the world as is
      echo %promptstr
   endiff
   endlocal
}

And in tcstart.btm it is then loaded as follows:

Code:
:: Load library that converts the oh-my-posh prompt to TCC/CMD prompt style
library /u /r path-to-library\library-file-name
:: Check theme for having a a final space character
set appendspace=%@execstr[find /i "final_space" path-to-themes\your-favorite-theme.omp.json | find /i /c "true"]
:: Set the prompt string
prompt %%@execstr[BuildPrompt path-to-themes\your-favorite-theme.omp.json %appendspace ]
:: Clean up
unset appendspace

There are a few gotchas:
  1. It seems that %@execarray discards trailing spaces in the lines it collects. So even if your oh-my-posh theme defines that the prompt must end with a space ("final_space": true) that space will not make it to the TCC prompt string. Hence the line:

    Code:
    set appendspace=%@execstr[find /i "final_space" path-to-themes\your-favorite-theme.omp.json | find /i /c "true"]

    which checks whether a final space should be added.

  2. If you use a prompt that requires nerd fonts, the codepage must support those. The following addition to tcstart.btm takes care of that:

    Code:
    :: Make sure the code page supports nerd fonts used with oh-my-posh
    iff not %_CODEPAGE==65001 then
       chcp 65001 >& nul
    endiff

  3. Also, the exit segment in oh-my-posh does not work in TCC. Oh-my-posh retrieves the Windows variable lastErrorCode but I have not found a way to set this such that it is anything but 0 in TCC.
 
It turns out that the solution above does not handle oh-my-posh prompts quite right. Specifically: empty leading line(s) shall not be ignored.

The listing below contains the new version of the library function that works (more) correctly:

Code:
BuildPrompt {
   :: Do not disturb
   @echo off
   setlocal

   :: Save parameters
   set theme=%1
   set appendspace=%2

   :: The TCC (and cmd.exe) PROMPT command does not allow for multiple lines in a prompt string.
   :: So we collect the output from oh-my-posh in an array.
   set LINESNUM=10
   setarray /f promptlines[ %LINESNUM ]
   echo %@execarray[ promptlines, oh-my-posh.exe --shell universal --config %theme ] >& nul

   :: States for line processing.
   :: The first line is just added as is. Following lines are added with a line break $ sequence
   :: ($_) in between. When a non-empty line is found, the state changes such that when an empty
   :: line is found, the loop stops. At that point a space is optionally appended to the prompt.
   set state=first_line

   :: Process the lines to build a prompt string for TCC
   do index = 0 to %LINESNUM
      switch %state
      case first_line
         :: Collect the first line as is
         set promptstr=%promptlines[ %index ]
         set state=following_lines
         :: Go directly to next state
         iterate

      case following_lines
         iff not "%promptlines[ %index ]" == "" then
            set state=break_on_empty
         endiff

      case break_on_empty
         :: Empty line encountered?
         iff "%promptlines[ %index ]" == "" then
            :: Add trailing space?
            iff defined appendspace .and. %appendspace then
               set promptstr=%promptstr%$s
            endiff
            :: No more to do here
            leave
         endiff
      endswitch

      :: Add line to prompt string with a linebreak in between.
      set promptstr=%promptstr%$_%promptlines[ %index ]
   enddo

   :: It seems that arrays are not destroyed automatically by endlocal so a bit of explicit cleanup
   :: is needed.
   unsetarray promptlines

   :: Present prompt to the world
   echo %promptstr
   endlocal
}
 

Similar threads