Welcome!

By registering with us, you'll be able to discuss, share and private message with other members of our community.

SignUp Now!

How to? Use oh-my-posh with TCC

Jun
40
0
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
}
 
This seems to be broken for the newest oh-my-posh. I've tried to alter the arguments for oh-my-posh to set it to the following, but did not succeeded:
Code:
oh-my-posh.exe print primary --shell universal --config %theme
There were two issues with it: 1. the UNICODE characters were lost, and replaced with '?', 2. the single line prompt was made up of four lines. I've used AgnosterPlus as the theme, which have a time stamp on the right, that might have lead to the four lines. Unfortunately I have no time to mess with it right now, thought I'd let you know.
 
I took some time from my night time, and figure out some things:
  • I am not entirely sure how many versions are there going in parallel of oh-my-posh, but just in case, I was using the one from Home | Oh My Posh. That is currently at version 19.8.2. I was thinking on making a switch depending on the version number of oh-my-posh, but not even sure when this arguments are changed, or even we're using the same product ATM.
  • I also went a little overboard with the arguments, but I had my fun with it.
  • I have figured out, that to make the prompt UNICODE compliant, you need to change the code-page to UNICODE with chcp within the library function and also omit it's output:
Code:
chcp 65001>&null
  • At an intermediate experimentation, where I still trying to figure out where or how the UNICODE characters are lost, I've figured I'd use ECHOS command instead of setting a parameter. This command emits the text without a line-break, which is perfect for building up the prompt on a single line, and it already prints out the prompt in the end.
  • Compared to whatever version the above was written for, it is possible to get a secondary prompt, so it is also possible to set PROMPT2, though that is only possible to set with the SET command. I also moved the extra space from the loop to the end of the loop, so it is always added. that is my interpretation though, and may be incorrect.
  • I also moved the line figuring out whether spaces are needed at the end of the prompt inside of the function. Then I had an error on the '-' file not being found, but instead of bothered to find where this issue stemming from, I'm just discarding the output.
  • I also saw the comment on the array not being deallocated, and thought it could be reused to optimize memory allocations, but I couldn't make that to work.
  • Some themes have additional information on the right side, and I am thinking of how to incorporate that in to the prompt. I was thinking of emitting that to stderr, and relocate the cursor back.
  • I've changed the function name to OhMyTcc because I did not want to collide with yours, and also I could.
  • Also using the %_execarray variable to determine the number of lines emitted by oh-my-posh.exe.

This is the final code that I'm using:
Code:
::https://jpsoft.com/forums/threads/use-oh-my-posh-with-tcc.11066/
OhMyTcc {
   :: Do not disturb
   @echo off
   setlocal
   chcp 65001>&null

   :: Save parameters
   set theme=%2
   set part=%1
   :: Check theme for having a a final space character
   set appendspace=%@execstr[find /i "final_space" "%theme" 2>&null | find /i /c "true" ]

   :: 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 ]
   :: since somewhere before 19.8.2 from https://ohmyposh.dev/
   echo %@execarray[ promptlines, oh-my-posh.exe prompt print %part -c "%theme" --column %_column -e %? --pwd %_cwd --shell %_cmdproc --shell-version %_version -w %_columns ] >& 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 %@eval[%_execarray-1]
      switch %state
      case first_line
         :: Collect the first line as is
         echos %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
            :: No more to do here
            leave
         endiff
      endswitch

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

   :: Add trailing space?
   iff defined appendspace .and. %appendspace then
      echos $s
   endiff

   :: 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
   endlocal
}

Edit: This however changes how you would use it. These are all the possible ways to use this one:
Code:
prompt %%@execstr[OhMyTcc primary "%[POSH_THEMES_FOLDER]\agnoster.omp.json"]
set prompt=%%@execstr[OhMyTcc primary "%[POSH_THEMES_FOLDER]\agnoster.omp.json"]
set prompt2=%%@execstr[OhMyTcc secondary "%[POSH_THEMES_FOLDER]\agnoster.omp.json"]

It is late night for me, so I'm a bit scatterbrained right now. Sorry if anythings comes through rude or rough.
 

Similar threads

Back
Top