--- a/mercurial/ui.py Mon Dec 14 23:04:17 2015 +0000
+++ b/mercurial/ui.py Thu Dec 17 17:27:32 2015 -0600
@@ -11,6 +11,7 @@
import getpass
import inspect
import os
+import re
import socket
import sys
import tempfile
@@ -812,10 +813,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])