Stop make shell interpreting arrow up

81 Views Asked by At

I will describe first environment:

Windows pc, running make in powershell. Make is using bash as its shell. I also use Windows terminal. So powershell is running in Windows terminal, calling of make target.

Problem:

When I run any target (that has at least some shell call) and press eg. arrow up, at the end of make call, I get [A printed in powershell.

My goal is to get arrow up action in powershell to load previous command. This way, I can quickly just type make clean followed by arrow up to get history command from powershell make build. This used to work previously, but I have no idea what exactly changed. It seems that make calls bash and bash is interpreting my arrow up as escape sequence that gets sent to powershell without esc seqeunce.

I tried to insert into my .bashrc set keyseq-timeout either to 0, or some big value, nothing helped.

Also, this happens in powershell standalone, or even in cmd.

How to get it working as previously?

1

There are 1 best solutions below

7
mklement0 On
  • It works when you're calling from a Bash environment, such as WSL or Git Bash.

    • From WSL, ^[[A[1] is getting printed if you press the up-arrow while a command is still running, but the buffered keystroke does take effect after the command terminates; the behavior is the same in Git Bash, except that ^[[A does not print.
  • When calling from a native Windows shell, such as cmd.exe or PowerShell, that shell does not receive the buffered keystroke; instead, it is handled by the terminal (console) itself.

    • This is in effect a no-op: the cursor moves up one line in the terminal, but then the Windows-native shell regains control and prints its prompt string on the original line, followed by placing the cursor at the end.

    • I'm unclear on the exact reason, but I suspect it is related to the fact that two shells are involved, and that the buffered keystroke, due to the Bash shell having exited along with the command, isn't handled by Bash and also isn't passed to the outer, Windows-native shell, causing the terminal emulator to interpret it.

      • Frankly, I'd be surprised if this behaved differently in the past, i.e. if this ever worked - but if you can pinpoint a specific scenario in which it did, do tell us.
  • If you want to stick with using Bash as the shell in your Makefiles, the next section provides - imperfect - workarounds.

    • In order to make typeahead work they way you expect, you'll need to modify your Makefiles to use either cmd.exe or PowerShell for shell commands, which involves both placing a SHELL statement at the top - see this answer - and changing the actual shell commands to PowerShell commands.

Workarounds with Bash as the Makefile shell:

If the aim is to simply recall the previous command and execute it right away, you can use PowerShell's Invoke-History cmdlet, whose built-in alias is r (presumably short for recall):

# Execute `make clean`, then recall and execute the previous command.
make clean; r

Note: If you want to make the re-execution contingent on make clean signaling success, use
make clean && r in PowerShell (Core) 7+, and
make clean; if (0 -eq $LASTEXITCODE) { r } in Windows PowerShell. The same applies analogously to the other commands below.

Of course, if you know ahead of time that make build is the next command you want to execute, simply make it part of the same command line; e.g.:

# PS 7+ syntax - only executes `make build` if `make clean` succeeded.
make clean && make build

If you fully want to emulate the up-arrow behavior, i.e. if you want to recall the previous command without instantly executing it, i.e. if you only want to place it in the command-line edit buffer:

  • First, define a helper function that simulates pressing the up-arrow key (twice, because at the time it executes the previous command is the penultimate one, because the current one has already been recorded):

    # Helper function
    function u {
      (New-Object -ComObject WScript.Shell).SendKeys('{UP 2}')
    }
    
  • Then call u in lieu of r:

    make clean; u
    

[1] ^[ represents the ESC character, and the whole sequence - ESC [ A - is presumably what xterm-compatible terminal emulators emit when the up-arrow key is pressed. Many shells intercept this keystroke and interpret it to mean: recall the most recently submitted command and place it in the command-line edit buffer. In the absence of a shell, the cursor moves one line up from the current line.