ui: add new config flag for interface selection
This patch introduces a new config flag ui.interface to select the interface
for interactive commands. It currently only applies to chunks selection.
The config can be overridden on a per feature basis with the flag
ui.interface.<feature>.
features for the moment can only be 'chunkselector', moving forward we expect
to have 'histedit' and other commands there.
If an incorrect value is given to ui.interface we print a warning and use the
default interface: text. If HGPLAIN is specified we also use the default
interface: text.
Note that we fail quickly if a feature does not handle all the interfaces
that we permit in ui.interface; in future, we could design a fallback path
(e.g. blackpearl to curses, curses to text), but let's leave that until we
need it.
--- a/mercurial/help/config.txt Fri Mar 11 10:30:08 2016 +0000
+++ b/mercurial/help/config.txt Mon Mar 14 15:01:27 2016 +0000
@@ -1613,6 +1613,15 @@
``interactive``
Allow to prompt the user. (default: True)
+``interface``
+ Select the default interface for interactive features (default: text).
+ Possible values are 'text' and 'curses'.
+
+``interface.chunkselector``
+ Select the interface for change recording (e.g. :hg:`commit` -i).
+ Possible values are 'text' and 'curses'.
+ This config overrides the interface specified by ui.interface.
+
``logtemplate``
Template string for commands that print changesets.
--- a/mercurial/ui.py Fri Mar 11 10:30:08 2016 +0000
+++ b/mercurial/ui.py Mon Mar 14 15:01:27 2016 +0000
@@ -697,6 +697,77 @@
return False
return util.isatty(fh)
+ def interface(self, feature):
+ """what interface to use for interactive console features?
+
+ The interface is controlled by the value of `ui.interface` but also by
+ the value of feature-specific configuration. For example:
+
+ ui.interface.histedit = text
+ ui.interface.chunkselector = curses
+
+ Here the features are "histedit" and "chunkselector".
+
+ The configuration above means that the default interfaces for commands
+ is curses, the interface for histedit is text and the interface for
+ selecting chunk is crecord (the best curses interface available).
+
+ Consider the following exemple:
+ ui.interface = curses
+ ui.interface.histedit = text
+
+ Then histedit will use the text interface and chunkselector will use
+ the default curses interface (crecord at the moment).
+ """
+ alldefaults = frozenset(["text", "curses"])
+
+ featureinterfaces = {
+ "chunkselector": [
+ "text",
+ "curses",
+ ]
+ }
+
+ # Feature-specific interface
+ if feature not in featureinterfaces.keys():
+ # Programming error, not user error
+ raise ValueError("Unknown feature requested %s" % feature)
+
+ availableinterfaces = frozenset(featureinterfaces[feature])
+ if alldefaults > availableinterfaces:
+ # Programming error, not user error. We need a use case to
+ # define the right thing to do here.
+ raise ValueError(
+ "Feature %s does not handle all default interfaces" %
+ feature)
+
+ if self.plain():
+ return "text"
+
+ # Default interface for all the features
+ defaultinterface = "text"
+ i = self.config("ui", "interface", None)
+ if i in alldefaults:
+ defaultinterface = i
+
+ choseninterface = defaultinterface
+ f = self.config("ui", "interface.%s" % feature, None)
+ if f in availableinterfaces:
+ choseninterface = f
+
+ if i is not None and defaultinterface != i:
+ if f is not None:
+ self.warn(_("invalid value for ui.interface: %s\n") %
+ (i,))
+ else:
+ self.warn(_("invalid value for ui.interface: %s (using %s)\n") %
+ (i, choseninterface))
+ if f is not None and choseninterface != f:
+ self.warn(_("invalid value for ui.interface.%s: %s (using %s)\n") %
+ (feature, f, choseninterface))
+
+ return choseninterface
+
def interactive(self):
'''is interactive input allowed?
--- a/tests/test-commit-interactive-curses.t Fri Mar 11 10:30:08 2016 +0000
+++ b/tests/test-commit-interactive-curses.t Mon Mar 14 15:01:27 2016 +0000
@@ -1,5 +1,6 @@
Set up a repo
+ $ cp $HGRCPATH $HGRCPATH.pretest
$ cat <<EOF >> $HGRCPATH
> [ui]
> interactive = true
@@ -223,3 +224,90 @@
hello world
+Check ui.interface logic for the chunkselector
+
+The default interface is text
+ $ cp $HGRCPATH.pretest $HGRCPATH
+ $ chunkselectorinterface() {
+ > python <<EOF
+ > from mercurial import hg, ui, parsers;\
+ > repo = hg.repository(ui.ui(), ".");\
+ > print repo.ui.interface("chunkselector")
+ > EOF
+ > }
+ $ chunkselectorinterface
+ text
+
+If only the default is set, we'll use that for the feature, too
+ $ cp $HGRCPATH.pretest $HGRCPATH
+ $ cat <<EOF >> $HGRCPATH
+ > [ui]
+ > interface = curses
+ > EOF
+ $ chunkselectorinterface
+ curses
+
+It is possible to override the default interface with a feature specific
+interface
+ $ cp $HGRCPATH.pretest $HGRCPATH
+ $ cat <<EOF >> $HGRCPATH
+ > [ui]
+ > interface = text
+ > interface.chunkselector = curses
+ > EOF
+
+ $ chunkselectorinterface
+ curses
+
+ $ cp $HGRCPATH.pretest $HGRCPATH
+ $ cat <<EOF >> $HGRCPATH
+ > [ui]
+ > interface = curses
+ > interface.chunkselector = text
+ > EOF
+
+ $ chunkselectorinterface
+ text
+
+If a bad interface name is given, we use the default value (with a nice
+error message to suggest that the configuration needs to be fixed)
+
+ $ cp $HGRCPATH.pretest $HGRCPATH
+ $ cat <<EOF >> $HGRCPATH
+ > [ui]
+ > interface = blah
+ > EOF
+ $ chunkselectorinterface
+ invalid value for ui.interface: blah (using text)
+ text
+
+ $ cp $HGRCPATH.pretest $HGRCPATH
+ $ cat <<EOF >> $HGRCPATH
+ > [ui]
+ > interface = curses
+ > interface.chunkselector = blah
+ > EOF
+ $ chunkselectorinterface
+ invalid value for ui.interface.chunkselector: blah (using curses)
+ curses
+
+ $ cp $HGRCPATH.pretest $HGRCPATH
+ $ cat <<EOF >> $HGRCPATH
+ > [ui]
+ > interface = blah
+ > interface.chunkselector = curses
+ > EOF
+ $ chunkselectorinterface
+ invalid value for ui.interface: blah
+ curses
+
+ $ cp $HGRCPATH.pretest $HGRCPATH
+ $ cat <<EOF >> $HGRCPATH
+ > [ui]
+ > interface = blah
+ > interface.chunkselector = blah
+ > EOF
+ $ chunkselectorinterface
+ invalid value for ui.interface: blah
+ invalid value for ui.interface.chunkselector: blah (using text)
+ text