Skip to content

Commit

Permalink
fix: improve prompt detection (#251)
Browse files Browse the repository at this point in the history
* feat: use prompt detection instead of regex patterns

Signed-off-by: Chapman Pendery <[email protected]>

* fix: command tracking for complex prompts

Signed-off-by: Chapman Pendery <[email protected]>

* fix: add support for other shells

Signed-off-by: Chapman Pendery <[email protected]>

* fix: drop unused eslint escape

Signed-off-by: Chapman Pendery <[email protected]>

* fix: @p expand version issues

Signed-off-by: Chapman Pendery <[email protected]>

* ci: drop flaky test

Signed-off-by: Chapman Pendery <[email protected]>

---------

Signed-off-by: Chapman Pendery <[email protected]>
  • Loading branch information
cpendery committed May 1, 2024
1 parent 60653a1 commit bf7a832
Show file tree
Hide file tree
Showing 14 changed files with 172 additions and 129 deletions.
12 changes: 0 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,18 +106,6 @@ key = "escape"

Key names are matched against the Node.js [keypress](https://nodejs.org/api/readline.html#readlineemitkeypresseventsstream-interface) events.

### Custom Prompts (Windows)

If you are using a custom prompt in your shell (anything that is not the default PS1), you will need to set up a custom prompt in the inshellisense config file. This is because Windows strips details from your prompt which are required for inshellisense to work. To do this, update your config file in your home directory and add the following configuration:

```toml
[[prompt.bash]]
regex = "(?<prompt>^>\\s*)" # the prompt match group will be used to detect the prompt
postfix = ">" # the postfix is the last expected character in your prompt
```

This example adds custom prompt detection for bash where the prompt is expected to be only `> `. You can add similar configurations for other shells as well as well as multiple configurations for each shell.

## Contributing

This project welcomes contributions and suggestions. Most contributions require you to agree to a
Expand Down
1 change: 1 addition & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
"color-convert": "^2.0.1",
"commander": "^11.0.0",
"find-process": "^1.4.7",
"strip-ansi": "^7.1.0",
"toml": "^3.0.0",
"wcwidth": "^1.0.1",
"which": "^4.0.0",
Expand Down
15 changes: 15 additions & 0 deletions shell/shellIntegration.bash
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@ __is_escape_value() {
token="\\\\"
elif [ "$byte" = ";" ]; then
token="\\x3b"
elif [ "$byte" = $'\n' ]; then
token="\x0a"
elif [ "$byte" = $'\e' ]; then
token="\\x1b"
else
token="$byte"
fi
Expand All @@ -54,13 +58,24 @@ __is_update_cwd() {
builtin printf '\e]6973;CWD;%s\a' "$(__is_escape_value "$PWD")"
}

__is_report_prompt() {
if ((BASH_VERSINFO[0] >= 4)); then
__is_prompt=${__is_original_PS1@P}
else
__is_prompt=${__is_original_PS1}
fi
__is_prompt="$(builtin printf "%s" "${__is_prompt//[$'\001'$'\002']}")"
builtin printf "\e]6973;PROMPT;%s\a" "$(__is_escape_value "${__is_prompt}")"
}

if [[ -n "${bash_preexec_imported:-}" ]]; then
precmd_functions+=(__is_precmd)
fi

__is_precmd() {
__is_update_cwd
__is_update_prompt
__is_report_prompt
}

__is_update_prompt() {
Expand Down
13 changes: 8 additions & 5 deletions shell/shellIntegration.fish
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,18 @@ function __is_copy_function; functions $argv[1] | sed "s/^function $argv[1]/func
function __is_prompt_start; printf '\e]6973;PS\a'; end
function __is_prompt_end; printf '\e]6973;PE\a'; end

__is_copy_function fish_prompt is_user_prompt

function __is_escape_value
echo $argv \
| string replace --all '\\' '\\\\' \
| string replace --all ';' '\\x3b' \
| string replace -a '\\' '\\\\' \
| string replace -a ';' '\\x3b' \
| string replace -a \e '\\x1b' \
| string split \n | string join '\x0a' \
;
end
function __is_update_cwd --on-event fish_prompt; set __is_cwd (__is_escape_value "$PWD"); printf "\e]6973;CWD;$__is_cwd\a"; end
__is_copy_function fish_prompt is_user_prompt
function __is_update_cwd --on-event fish_prompt; set __is_cwd (__is_escape_value "$PWD"); printf "\e]6973;CWD;%s\a" $__is_cwd; end
function __is_report_prompt --on-event fish_prompt; set __is_prompt (__is_escape_value (is_user_prompt)); printf "\e]6973;PROMPT;%s\a" $__is_prompt; end
if [ "$ISTERM_TESTING" = "1" ]
function is_user_prompt; printf '> '; end
Expand Down
14 changes: 11 additions & 3 deletions shell/shellIntegration.nu
Original file line number Diff line number Diff line change
@@ -1,18 +1,26 @@
let __is_escape_value = {|x| $x | str replace --all "\\" "\\\\" | str replace --all ";" "\\x3b" }
let __is_escape_value = {|x| $x | str replace --all "\\" "\\\\" | str replace --all ";" "\\x3b" | str replace --all "\n" '\x0a' | str replace --all "\e" "\\x1b" }
let __is_original_PROMPT_COMMAND = if 'PROMPT_COMMAND' in $env { $env.PROMPT_COMMAND } else { "" }
let __is_original_PROMPT_INDICATOR = if 'PROMPT_INDICATOR' in $env { $env.PROMPT_INDICATOR } else { "" }

let __is_update_cwd = {
let pwd = do $__is_escape_value $env.PWD
$"\e]6973;CWD;($pwd)\a"
}
let __is_original_PROMPT_COMMAND = if 'PROMPT_COMMAND' in $env { $env.PROMPT_COMMAND } else { "" }
let __is_report_prompt = {
let __is_indicatorCommandType = $__is_original_PROMPT_INDICATOR | describe
mut __is_prompt_ind = if $__is_indicatorCommandType == "closure" { do $__is_original_PROMPT_INDICATOR } else { $__is_original_PROMPT_INDICATOR }
let __is_esc_prompt_ind = do $__is_escape_value $__is_prompt_ind
$"\e]6973;PROMPT;($__is_esc_prompt_ind)\a"
}
let __is_custom_PROMPT_COMMAND = {
let promptCommandType = $__is_original_PROMPT_COMMAND | describe
mut cmd = if $promptCommandType == "closure" { do $__is_original_PROMPT_COMMAND } else { $__is_original_PROMPT_COMMAND }
let pwd = do $__is_update_cwd
let prompt = do $__is_report_prompt
if 'ISTERM_TESTING' in $env {
$cmd = ""
}
$"\e]6973;PS\a($cmd)($pwd)"
$"\e]6973;PS\a($cmd)($pwd)($prompt)"
}
$env.PROMPT_COMMAND = $__is_custom_PROMPT_COMMAND

Expand Down
7 changes: 5 additions & 2 deletions shell/shellIntegration.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ if ($env:ISTERM_TESTING -eq "1") {
}

function Global:__IS-Escape-Value([string]$value) {
[regex]::Replace($value, '[\\\n;]', { param($match)
[regex]::Replace($value, "[$([char]0x1b)\\\n;]", { param($match)
-Join (
[System.Text.Encoding]::UTF8.GetBytes($match.Value) | ForEach-Object { '\x{0:x2}' -f $_ }
)
Expand All @@ -17,8 +17,11 @@ function Global:__IS-Escape-Value([string]$value) {

function Global:Prompt() {
$Result = "$([char]0x1b)]6973;PS`a"
$Result += $Global:__IsOriginalPrompt.Invoke()
$OriginalPrompt += $Global:__IsOriginalPrompt.Invoke()
$Result += $OriginalPrompt
$Result += "$([char]0x1b)]6973;PE`a"

$Result += "$([char]0x1b)]6973;PROMPT;$(__IS-Escape-Value $OriginalPrompt)`a"
$Result += if ($pwd.Provider.Name -eq 'FileSystem') { "$([char]0x1b)]6973;CWD;$(__IS-Escape-Value $pwd.ProviderPath)`a" }
return $Result
}
16 changes: 12 additions & 4 deletions shell/shellIntegration.xsh
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import os
from xonsh.main import XSH

def __is_prompt_start() -> str:
return "\001" + "\x1b]6973;PS\x07"
Expand All @@ -7,23 +8,30 @@ def __is_prompt_start() -> str:
def __is_prompt_end() -> str:
return "\001" + "\x1b]6973;PE\x07" + "\002"


def __is_escape_value(value: str) -> str:
byte_list = [bytes([byte]).decode("utf-8") for byte in list(value.encode("utf-8"))]
return "".join(
[
"\\x3b" if byte == ";" else "\\\\" if byte == "\\" else byte
"\\x3b" if byte == ";" else "\\\\" if byte == "\\" else "\\x1b" if byte == "\x1b" else "\x0a" if byte == "\n" else byte
for byte in byte_list
]
)

def __is_update_cwd() -> str:
return f"\x1b]6973;CWD;{__is_escape_value(os.getcwd())}\x07" + "\002"
return f"\x1b]6973;CWD;{__is_escape_value(os.getcwd())}\x07"

__is_original_prompt = $PROMPT
def __is_report_prompt() -> str:
prompt = ""
formatted_prompt = XSH.shell.prompt_formatter(__is_original_prompt)
prompt = "".join([text for _, text in XSH.shell.format_color(formatted_prompt)])
return f"\x1b]6973;PROMPT;{__is_escape_value(prompt)}\x07" + "\002"

$PROMPT_FIELDS['__is_prompt_start'] = __is_prompt_start
$PROMPT_FIELDS['__is_prompt_end'] = __is_prompt_end
$PROMPT_FIELDS['__is_update_cwd'] = __is_update_cwd
$PROMPT_FIELDS['__is_report_prompt'] = __is_report_prompt
if 'ISTERM_TESTING' in ${...}:
$PROMPT = "> "

$PROMPT = "{__is_prompt_start}{__is_update_cwd}" + $PROMPT + "{__is_prompt_end}"
$PROMPT = "{__is_prompt_start}{__is_update_cwd}{__is_report_prompt}" + $PROMPT + "{__is_prompt_end}"

0 comments on commit bf7a832

Please sign in to comment.