User defined prompt with dynamic data

Discussion forum for all Windows batch related topics.

Moderator: DosItHelp

Post Reply
Message
Author
jeb
Expert
Posts: 1042
Joined: 30 Aug 2007 08:05
Location: Germany, Bochum

User defined prompt with dynamic data

#1 Post by jeb » 21 Jun 2023 05:54

Hi,

I played a bit with the prompt to archive similar behavior like the bash prompt.

Code: Select all

export PS1="Time \$(date --iso=sec)"
Each time I get a new prompt line, the date command will be executed.

This exact example can be solved by simply use set "prompt=Time $T"
But currently, it's not possible to execute any program or even to show the current value of a variable

I've build a partial solution, but I need to manually press <ENTER>

Code: Select all

@echo off
REM *** Trampoline jump for function calls of the form ex. "C:\:function:\..\MyBatchFile.bat"
FOR /F "tokens=3 delims=:" %%L in ("%~0") DO goto :%%L

for /f "delims=" %%C in (
  'forfiles /p "%~dp0." /m "%~nx0" /c "cmd /c echo(0x1B"'
) do set "esc=%%C"
for /f "delims=" %%C in (
  'forfiles /p "%~dp0." /m "%~nx0" /c "cmd /c echo(0x08"'
) do set "BS=%%C"


doskey %esc%[1;1R="%~d0\:action:\..\%~pnx0" arg1 
REM *** doskey /macros
goto :set_prompt
exit /b

:action
for /f "delims=" %%C in (
  'forfiles /p "%~dp0." /m "%~nx0" /c "cmd /c echo(0x1B"'
) do set "esc=%%C"
for /f "delims=" %%C in (
  'forfiles /p "%~dp0." /m "%~nx0" /c "cmd /c echo(0x08"'
) do set "BS=%%C"
REM *** Remove the "^[[1;1R" string and add custom data
set /a count+=1
set "CUSTOM_DATA=[%count%] ^>"
echo %esc%[u%esc%[K%CUSTOM_DATA%
rem ###%TIME% %0 %*
REM *** uncomment the exit /b for simpler testing
REM *** exit /b 

:set_prompt
prompt $e[s$e[H$e[6n$e[u$P$S$e[s
The key is the "$e[6n" sequence, "ESC [ 6 n" = DECXCPR Show cursor position
This goes directly to the input buffer, it's treated like keyboard input.
To get always the same result, I use the "$e[H" sequence to bring the cursor to the home position (1,1).
So the answer to "ESC[6n" is always "ESC[1,1R", in the console you see "^[[1,1R"
I defined a doskey macro with the name "^[[1,1R" to fetch exactly this sequence.

In action, it looks like

Code: Select all

C:\Users\jeb [21] >

C:\Users\jeb [22] >

C:\Users\jeb [23] >

C:\Users\jeb [24] >

C:\Users\jeb ^[[1;1R
Currently, I don't have a good idea to execute the "^[[1;1R" doskey-macro without manually pressing <ENTER>.

Any ideas?

miskox
Posts: 554
Joined: 28 Jun 2010 03:46

Re: User defined prompt with dynamic data

#2 Post by miskox » 21 Jun 2023 06:36

Code: Select all

@echo off
set curr_time=%time%
set /p "time_var=Time is %time%. Enter something:"
echo time_var=%time_Var%_
set curr_time=%time%
set /p "time_var=Time is %time%. Enter something:"
echo time_var=%time_Var%_
echo.
echo LOOP 1-10
for /L %%f in (1,1,10) do set/p variable_name=Counter %%f

Code: Select all

c:\>some_bat.cmd
Time is 14:35:06,13. Enter something:x
time_var=x_
Time is 14:35:06,52. Enter something:x
time_var=x_

LOOP 1-10
Counter 1
Counter 2
Counter 3
Counter 4
Counter 5
Counter 6
Counter 7
Counter 8
Counter 9
Counter 10
c:\>
Or am I missing something?

Saso

jeb
Expert
Posts: 1042
Joined: 30 Aug 2007 08:05
Location: Germany, Bochum

Re: User defined prompt with dynamic data

#3 Post by jeb » 21 Jun 2023 06:51

Hi miskox,
miskox wrote:
21 Jun 2023 06:36
Or am I missing something?
Yes, you missed completely my point :D

I don't want a batch file doing something.
I want a customizable prompt, able to show more than the predefined $P,$G,$T,$V ...
A prompt that could start a command each time when the prompt is shown.

Aacini
Expert
Posts: 1885
Joined: 06 Dec 2011 22:15
Location: México City, México
Contact:

Re: User defined prompt with dynamic data

#4 Post by Aacini » 21 Jun 2023 08:50

Mmmm... This idea is pretty crazy! :D

I reviewed the ANSI escape codes and found no way to generate an ENTER char. Indeed, there is no way to generate nothing other than the cursor position (embedded by the ESC codes), so I am afraid that your (crazy) idea to use the same name for a command would not be very useful... :(

Anyway, I like this! There is some time since no original research like this was done...

Antonio

mataha
Posts: 32
Joined: 27 Apr 2023 12:34

Re: User defined prompt with dynamic data

#5 Post by mataha » 21 Jun 2023 10:39

I've tried time and time again to make this work, so might as well post what I have. The way I envisioned this was through DOSKEY macros:

Code: Select all

set CMD_PROMPT=$E]2;$P$E\$P$G$E[0m$S
set PROMPT=%CMD_PROMPT%

::: This is a crude implementation; only the git porcelain bit is relevant
"%windir%\System32\doskey.exe" cd = (^
    chdir $*^
) ^& (git rev-parse --show-toplevel ^>nul 2^>^&1) ^&^& (^
    for /f "delims=" %%r in ('"git name-rev --always --name-only HEAD 2>nul"') do @(^
        set "PROMPT=%CMD_PROMPT%$C$E[31m%%~r$E[39m$F$S"^
    )^
) ^|^| set "PROMPT=%CMD_PROMPT%"
A real-world example of this technique can be found here. As you probably see on the first glance, this has several shortcomings, i.e.:
  • cd is hardly the only method of changing directories; I would have to alias pushd, popd, possibly other user-provided commands (z?);
  • the state can change without calling cd, e.g. I could change the branch or delete the .git repository, forcing me to at least alias git as well;
  • nothing says that other commands can't alter the prompt themselves...
And that wouldn't let me achieve my ultimate goal: show the last exit code (i.e. ERRORLEVEL). OS/2 let you do this, alas...

However, your method requires only one alias, and it can be improved by using DA (Device Attributes) instead of DECXCPR:

Code: Select all

set PROMPT=$E[0c
This will always emit ESC[?1;0c (per the documentation here), eliminating the need to jump to (1, 1). From here I see a few possible approaches:
  • Hide the emitted garbage (how?) and let the user append something to a hidden alias (shortcoming: eliminates other DOSKEY aliases)
  • Silently clear the line, including the emitted state (I don't think this is possible - status won't be printed until other queries have been processed, right?)
  • Move somewhere else through input sequences (Home? End?)
  • Use an alternate screen buffer for prompt machinery
I've attached a screen showing how all query state commands behave on my terminal (I've used Windows Terminal for that, but the same applies to conhost.exe of course).
Attachments
WindowsTerminal_d3LGtObUp6.png
WindowsTerminal_d3LGtObUp6.png (21.89 KiB) Viewed 3466 times

miskox
Posts: 554
Joined: 28 Jun 2010 03:46

Re: User defined prompt with dynamic data

#6 Post by miskox » 21 Jun 2023 11:24

Oh, yes! Now I see. I was completely wrong. Prompt. Prompt. And not 'set /p'. Looks like it was a hard day.

Saso

jeb
Expert
Posts: 1042
Joined: 30 Aug 2007 08:05
Location: Germany, Bochum

Re: User defined prompt with dynamic data

#7 Post by jeb » 21 Jun 2023 11:31

Aacini wrote:
21 Jun 2023 08:50
I reviewed the ANSI escape codes and found no way to generate an ENTER char. Indeed, there is no way to generate nothing other than the cursor position
You look at the wrong site, I found at least
ESC Z Send VT100 Identification String
ESC [ c Send VT100 Identification String
ESC [ x (V) Send Terminal Parameter Report
ESC [ > c Send Secondary Device Attributes String
ESC [ 6 n Send Cursor Position Report
https://www.gnu.org/software/screen/man ... ences.html

But I only test them in my bash/Tilix, because I absolutely did not expect, that they could work in windows :shock:
Thanks to mataha!

@mataha, Yes ESC[c is much better than ESC[6n, it simplifies the logic.
mataha wrote:
21 Jun 2023 10:39
Hide the emitted garbage (how?) and let the user append something to a hidden alias (shortcoming: eliminates other DOSKEY aliases)
Silently clear the line, including the emitted state (I don't think this is possible - status won't be printed until other queries have been processed, right?)
Move somewhere else through input sequences (Home? End?)
Use an alternate screen buffer for prompt machinery
1+2+3 Hide,Clear or Move
I don't think this could solve the problem, as you already figured out: status won't be printed until other queries have been processed

4 Alternate screen buffer
Last time I tested the alternate screen buffer, conhost crashed immediately, that bug was fixed some time ago, but even then I don't see how it could help in any case.

The perfect solution would be to inject an <ENTER> to the input buffer, but even then I see the next problems on the horizon.
If the doskey-macro automatically starts, it could remove the garbage and place the cursor, but after the macro the next prompt appears, and we got a perfect endless loop :?
But this only needs to be solved after we have solved the first problem :D

miskox
Posts: 554
Joined: 28 Jun 2010 03:46

Re: User defined prompt with dynamic data

#8 Post by miskox » 21 Jun 2023 13:43

Maybe you could find more info in VT 420 and VT 520 programmer reference manuals.

Saso

mataha
Posts: 32
Joined: 27 Apr 2023 12:34

Re: User defined prompt with dynamic data

#9 Post by mataha » 21 Jun 2023 17:02

Quick update: as far as querying the terminal for state goes, conhost.exe supports DECXCPR and DA only, so it'd probably be best to stick to these two.

Regarding Enter - I have no idea how to tackle this, so I've submitted a question.

Post Reply