Repository: xonsh/xonsh

Issue:
$MULTILINE_PROMPT doesn't filter out OSC commands
I'm adding "terminal integration" to xonsh and as such need to add various prompt commands to prompt for the terminal to recognize when input/output starts/ends etc. [doc](https://github.com/wez/wezterm/blob/main/docs/shell-integration.md)

It's working fine in other prompt variables, but then in `$MULTILINE_PROMPT` it breaks down, I see the commands as literal ugly strings instead of them being their regular invisible selves with just `.`

## xonfig

<details>

```
$ xonfig
+------------------+-----------------+
| xonsh            | 0.13.4          |
| Python           | 3.10.10         |
| PLY              | 3.11            |
| have readline    | True            |
| prompt toolkit   | 3.0.36          |
| shell type       | prompt_toolkit  |
| history backend  | json            |
| pygments         | 2.14.0          |
| on posix         | True            |
| on linux         | False           |
| on darwin        | True            |
| on windows       | False           |
| on cygwin        | False           |
| on msys2         | False           |
| is superuser     | False           |
| default encoding | utf-8           |
| xonsh encoding   | utf-8           |
| encoding errors  | surrogateescape |
| xontrib 1        | cd              |
| RC file          | []              |
+------------------+-----------------+
```

</details>

## Expected Behavior

```xsh
$MULTILINE_PROMPT = "\001" + "\x1b]133;P;k=c\x07" + "\002" + "."
```

Signals that every new line in the multiline propmt is a "continuation prompt", but it should be invisible, the result should be just the same multiple `.` dots depending on your prompt width

## Current Behavior

Instead, I get this
```xsh
$MULTILINE_PROMPT = "\001" + "\x1b]133;P;k=c\x07" + "\002" + "."
~ $ if 2:
^A^[]133;P;k=c^G^B.^A^[]133;P;     echo 1
#                 ↑ this is our dot :)
```

while this works fine
```xsh
~ $ $PROMPT = "\001" + "\x1b]133;P;k=i\x07" + "\002" + "<"
<
```

It might be due to some issues in parsing in this command here? Maybe it's due to repetition of the `.`?:

https://github.com/xonsh/xonsh/blob/main/xonsh/prompt/base.py#L184

### Traceback (if applicable)

<details>

```
traceback
```

</details>

## Steps to Reproduce

- Start `xonsh --no-rc`
- Execute `$MULTILINE_PROMPT = "\001" + "\x1b]133;P;k=c\x07" + "\002" + "."`
- Type a multiline command


## For community
⬇️  **Please click the 👍 reaction instead of leaving a `+1` or 👍  comment**



Discussion:
This sounds like a problem solved here https://github.com/xonsh/xonsh/pull/4629 . I think the codes need to be wrapped differently for ptk shell and readline shells
How should they be wrapped in ptk?

The linked messages mentions the 1/2 which are already used as wrapping codes
>* OSC codes in ``$PROMPT`` is no longer removed when using ptk shell.
> These codes need to be escaped with ``\001..\002`` instead.

I've tried to replace the wrapper functiton with returning this, but that didn't help
```py
def ansi_esc_ptk(code: str):
  return fragment_list_to_text([
    ("[ZeroWidthEscape]","\001"), ("", f"{code}"), ("[ZeroWidthEscape]","\002"),
  ])
```



Resolving patch:
diff --git a/xonsh/environ.py b/xonsh/environ.py
--- a/xonsh/environ.py
+++ b/xonsh/environ.py
@@ -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.',
diff --git a/xonsh/ptk_shell/shell.py b/xonsh/ptk_shell/shell.py
--- a/xonsh/ptk_shell/shell.py
+++ b/xonsh/ptk_shell/shell.py
@@ -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
@@ -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


Test patch: