Skip to content

Commit

Permalink
Add Semantic Prompt support to multiline continuation lines (xonsh#5065)
Browse files Browse the repository at this point in the history
* fix: match the main return type to avoid a style class concat type error

Error: can only concatenate str (not "_TokenType") to str in prompt_toolkit/formatted_text/base.py, line 94, in <listcomp>
    [(style + " " + item_style, *rest) for item_style, *rest in result]

* feat: support semantic prompt sequences for the multiline prompt

* Ignore .python-version

* doc: add News item

* doc: add description for the new multiline prompt env vars
  • Loading branch information
eugenesvk committed Feb 21, 2023
1 parent 8ec33b8 commit 076ea25
Show file tree
Hide file tree
Showing 4 changed files with 71 additions and 2 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ include/
venv/
.venv*/

# Python project version files
.python-version

# Mac
.DS_Store
Expand Down
23 changes: 23 additions & 0 deletions news/multil.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
**Added:**

* Add support for `Semantic Prompt <https://gitlab.freedesktop.org/Per_Bothner/specifications/blob/master/proposals/semantic-prompts.md>`_ for line continuations in multiline prompts via two environment variables: ``$MULTILINE_PROMPT_PRE`` (e.g., ``\x01\x1b]133;P;k=c\x07\x02``), and ``$MULTILINE_PROMPT_POS`` (e.g., ``\x01\x1b]133;B\x07\x02``) that are inserted before/after each continuation line 'dots' block to mark input

**Changed:**

* <news item>

**Deprecated:**

* <news item>

**Removed:**

* <news item>

**Fixed:**

* <news item>

**Security:**

* <news item>
24 changes: 24 additions & 0 deletions xonsh/environ.py
Original file line number Diff line number Diff line change
Expand Up @@ -1386,6 +1386,30 @@ class PromptSetting(Xettings):
"Prompt text for 2nd+ lines of input, may be str or function which "
"returns a str.",
)
MULTILINE_PROMPT_PRE = Var(
is_string_or_callable,
ensure_string,
ensure_string,
"",
"Indicator inserted before the line continuation marks set "
"in ``$MULTILINE_PROMPT``. Can be used to mark the start of "
"a semantic continuation prompt "
"(see `Semantic Prompts <https://gitlab.freedesktop.org/Per_Bothner/specifications/blob/master/proposals/semantic-prompts.md>`_ "
"or `WezTerm <https://wezfurlong.org/wezterm/shell-integration.html>`_ "
"for more details). May be str or function which returns a str.",
)
MULTILINE_PROMPT_POS = Var(
is_string_or_callable,
ensure_string,
ensure_string,
"",
"Indicator inserted after the line continuation marks set "
"in ``$MULTILINE_PROMPT``. Can be used to mark the end of "
"a semantic continuation prompt and the beginning of user input "
"(see `Semantic Prompts <https://gitlab.freedesktop.org/Per_Bothner/specifications/blob/master/proposals/semantic-prompts.md>`_ "
"or `WezTerm <https://wezfurlong.org/wezterm/shell-integration.html>`_ "
"for more details). May be str or function which returns a str.",
)
PRETTY_PRINT_RESULTS = Var.with_default(
True,
'Flag for "pretty printing" return values.',
Expand Down
24 changes: 22 additions & 2 deletions xonsh/ptk_shell/shell.py
Original file line number Diff line number Diff line change
Expand Up @@ -468,10 +468,27 @@ def continuation_tokens(self, width, line_number, is_soft_wrap=False):
dots = dots() if callable(dots) else dots
if not dots:
return ""
prefix = XSH.env.get(
"MULTILINE_PROMPT_PRE", ""
) # e.g.: '\x01\x1b]133;P;k=c\x07\x02'
suffix = XSH.env.get(
"MULTILINE_PROMPT_POS", ""
) # e.g.: '\x01\x1b]133;B\x07\x02'
is_affix = any(x for x in [prefix, suffix])
if is_affix:
prefixtoks = tokenize_ansi(PygmentsTokens(self.format_color(prefix)))
suffixtoks = tokenize_ansi(PygmentsTokens(self.format_color(suffix)))
# [('class:pygments.color.reset',''), ('[ZeroWidthEscape]','\x1b]133;P;k=c\x07')]
# [('class:pygments.color.reset',''), ('[ZeroWidthEscape]','\x1b]133;B\x07')]

basetoks = self.format_color(dots)
baselen = sum(len(t[1]) for t in basetoks)
if baselen == 0:
return [(Token, " " * (width + 1))]
toks = [(Token, " " * (width + 1))]
if is_affix: # to convert ↓ classes to str to allow +
return prefixtoks + to_formatted_text(PygmentsTokens(toks)) + suffixtoks
else:
return PygmentsTokens(toks)
toks = basetoks * (width // baselen)
n = width % baselen
count = 0
Expand All @@ -488,7 +505,10 @@ def continuation_tokens(self, width, line_number, is_soft_wrap=False):
if n <= count:
break
toks.append((Token, " ")) # final space
return PygmentsTokens(toks)
if is_affix:
return prefixtoks + to_formatted_text(PygmentsTokens(toks)) + suffixtoks
else:
return PygmentsTokens(toks)

def format_color(self, string, hide=False, force_string=False, **kwargs):
"""Formats a color string using Pygments. This, therefore, returns
Expand Down

0 comments on commit 076ea25

Please sign in to comment.