changeset 52253:b3214b7d2390 stable

ui: fix escape sequences in in readline prompts (issue6930) Text that is meant to represent zero-width output in a readline prompt, such as terminal escape sequences, is supposed to be delimited by \001 ... \002: > Applications may indicate that the prompt contains characters that > take up no physical screen space when displayed by bracketing a > sequence of such characters with the special markers > RL_PROMPT_START_IGNORE and RL_PROMPT_END_IGNORE (declared in > readline.h `\001' and `\002', respectively). This may be used to > embed terminal-specific escape sequences in prompts. https://tiswww.cwru.edu/php/chet/readline/readline.html#index-rl_005fexpand_005fprompt When formatting a readline prompt in ui._readline, arrange to do this in the color.py labelling routines. Keeping mutable dynamically scoped state like this isn't great but threading it as a parameter through all the subroutines seems like much more trouble. (This doesn't address the missing line break -- that's a separate bug in libedit.) https://bz.mercurial-scm.org/show_bug.cgi?id=6930
author Taylor R Campbell <campbell+mercurial@mumble.net>
date Thu, 05 Dec 2024 20:46:21 +0000
parents 64baff9f7dad
children bcf6a219d235
files mercurial/color.py mercurial/ui.py
diffstat 2 files changed, 13 insertions(+), 2 deletions(-) [+]
line wrap: on
line diff
--- a/mercurial/color.py	Thu Dec 05 13:48:22 2024 +0000
+++ b/mercurial/color.py	Thu Dec 05 20:46:21 2024 +0000
@@ -386,6 +386,9 @@
         ]
         start = b'\033[' + b';'.join(start) + b'm'
         stop = b'\033[' + pycompat.bytestr(activeeffects[b'none']) + b'm'
+        if ui._readlineprompt:
+            start = b'\001' + start + b'\001'
+            stop = b'\002' + stop + b'\002'
     return _mergeeffects(text, start, stop)
 
 
@@ -518,7 +521,8 @@
         else:
             origattr = csbi.wAttributes
             ansire = re.compile(
-                br'\033\[([^m]*)m([^\033]*)(.*)', re.MULTILINE | re.DOTALL
+                br'\001?\033\[([^m]*)m\002?([^\033]*)(.*)',
+                re.MULTILINE | re.DOTALL,
             )
 
     def win32print(ui, writefunc, text, **opts):
--- a/mercurial/ui.py	Thu Dec 05 13:48:22 2024 +0000
+++ b/mercurial/ui.py	Thu Dec 05 20:46:21 2024 +0000
@@ -265,6 +265,8 @@
         self.logblockedtimes = False
         # color mode: see mercurial/color.py for possible value
         self._colormode = None
+        # readline prompt: is this currently for a readline prompt?
+        self._readlineprompt = False
         self._terminfoparams = {}
         self._styles = {}
         self._uninterruptible = False
@@ -1745,7 +1747,12 @@
             self.flush()
             prompt = b' '
         else:
-            prompt = self.label(prompt, b'ui.prompt') + b' '
+            wasreadlineprompt = self._readlineprompt
+            try:
+                self._readlineprompt = True
+                prompt = self.label(prompt, b'ui.prompt') + b' '
+            finally:
+                self._readlineprompt = wasreadlineprompt
 
         # prompt ' ' must exist; otherwise readline may delete entire line
         # - http://bugs.python.org/issue12833