[PATCH 1 of 2 V5] ui: add new config flag for interface selection

Simon Farnsworth simonfar at fb.com
Mon Mar 14 15:47:15 UTC 2016


# HG changeset patch
# User Simon Farnsworth <simonfar at fb.com>
# Date 1457967687 0
#      Mon Mar 14 15:01:27 2016 +0000
# Node ID 5302c318da91dfa7185389cf2e8e3f0685237030
# Parent  70c2f8a982766b512e9d7f41f2d93fdb92f5481f
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.

diff --git a/mercurial/help/config.txt b/mercurial/help/config.txt
--- a/mercurial/help/config.txt
+++ b/mercurial/help/config.txt
@@ -1607,6 +1607,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.
 
diff --git a/mercurial/ui.py b/mercurial/ui.py
--- a/mercurial/ui.py
+++ b/mercurial/ui.py
@@ -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?
 
diff --git a/tests/test-commit-interactive-curses.t b/tests/test-commit-interactive-curses.t
--- a/tests/test-commit-interactive-curses.t
+++ b/tests/test-commit-interactive-curses.t
@@ -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


More information about the Mercurial-devel mailing list