ui: try to handle $$ more robustly in prompts (
issue4970)
--- a/mercurial/ui.py Sat Dec 12 10:58:05 2015 -0800
+++ b/mercurial/ui.py Mon Nov 30 13:47:29 2015 -0600
@@ -11,6 +11,7 @@
import getpass
import inspect
import os
+import re
import socket
import sys
import tempfile
@@ -764,10 +765,23 @@
This returns tuple "(message, choices)", and "choices" is the
list of tuple "(response character, text without &)".
+
+ >>> ui.extractchoices("awake? $$ &Yes $$ &No")
+ ('awake? ', [('y', 'Yes'), ('n', 'No')])
+ >>> ui.extractchoices("line\\nbreak? $$ &Yes $$ &No")
+ ('line\\nbreak? ', [('y', 'Yes'), ('n', 'No')])
+ >>> ui.extractchoices("want lots of $$money$$?$$Ye&s$$N&o")
+ ('want lots of $$money$$?', [('s', 'Yes'), ('o', 'No')])
"""
- parts = prompt.split('$$')
- msg = parts[0].rstrip(' ')
- choices = [p.strip(' ') for p in parts[1:]]
+
+ # Sadly, the prompt string may have been built with a filename
+ # containing "$$" so let's try to find the first valid-looking
+ # prompt to start parsing. Sadly, we also can't rely on
+ # choices containing spaces, ASCII, or basically anything
+ # except an ampersand followed by a character.
+ m = re.match(r'(?s)(.+?)\$\$([^\$]*&[^ \$].*)', prompt)
+ msg = m.group(1)
+ choices = [p.strip(' ') for p in m.group(2).split('$$')]
return (msg,
[(s[s.index('&') + 1].lower(), s.replace('&', '', 1))
for s in choices])