[PATCH RFC WIP] status: add an option to see terse status (WIP)

Pulkit Goyal 7895pulkit at gmail.com
Fri May 26 21:18:01 UTC 2017


# HG changeset patch
# User Pulkit Goyal <7895pulkit at gmail.com>
# Date 1495832891 -19800
#      Sat May 27 02:38:11 2017 +0530
# Node ID 76fb3bdd547259620eec714c0d50fe1f9da25ebf
# Parent  2b5953a49f1407f825d65b45986d213cb5c79203
status: add an option to see terse status (WIP)

This is a work in progress to implement terse support for hg status. The current
implementation assumes that we need to collapse a certain directory when all the
files inside it has the same status which I think should be the default
behavior. Currently os module is used to list files and do related handling as I
am learning how to use matchers. There is a scope of lot of optimizations in the
above code.

The current implementation lacks things like skipping .hg folder, .pyc files or
any other files which are there and should not be tracked. I think those will be
fixed once I use matcher.

The reason I have send this WIP is to know what should be the behavior of the
output, i.e. is the current behavior okay or we also want to show status like:

M abc/
? abc/

or if say folder abc has 10 files out which only 5 are changed in the dirstate,
rest of them are untouched, and we show terse status as

M abc/

So, I will like to know what kind of behavior we want to support.

Secondly does the current direction/algorithm sounds good?

diff --git a/mercurial/commands.py b/mercurial/commands.py
--- a/mercurial/commands.py
+++ b/mercurial/commands.py
@@ -4663,6 +4663,7 @@
     ('c', 'clean', None, _('show only files without changes')),
     ('u', 'unknown', None, _('show only unknown (not tracked) files')),
     ('i', 'ignored', None, _('show only ignored files')),
+    ('t', 'terse', None, _('Show the tersed status')),
     ('n', 'no-status', None, _('hide status prefix')),
     ('C', 'copies', None, _('show source of copied files')),
     ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
@@ -4780,6 +4781,60 @@
     fmt = '%s' + end
     showchar = not opts.get('no_status')
 
+    if opts.get('terse'):
+        #visited = []
+        finalls = [[], [], [], [], [], [], []]
+        for i in range(0,7):
+            reslist = []
+            filedirdict = {}
+            newlist = []
+            fileslist = changestates[i][2]
+            lensuf = len(repo.root + os.path.sep)
+            for file in fileslist:
+                par = repo.root + os.path.sep + os.path.dirname(file)
+                #if par in visited:
+                #    continue
+
+                try:
+                    filedirdict[par].append(file)
+                except KeyError:
+                    filedirdict[par] = [file]
+
+            cpdict = filedirdict.copy()
+            for dirname, fnames in cpdict.iteritems():
+                #visited.append(dirname)
+                # This should be replaced with matcher
+                if len(os.listdir(dirname)) == len(fnames):
+                    dirpar = os.path.dirname(dirname)
+                    try:
+                        filedirdict[dirpar].append(dirname[lensuf:] +
+                                                os.path.sep)
+                    except KeyError:
+                        filedirdict[dirpar] = [dirname[lensuf:]+ os.path.sep]
+                    filedirdict[dirname] = []
+                    if dirname != repo.root:
+                        newlist.append(dirname)
+
+            while(len(newlist) != 0):
+                fname = newlist.pop()
+                par = os.path.dirname(fname)
+
+                if len(os.listdir(par)) == len(filedirdict[par]):
+                    parparent = os.path.dirname(par)
+                    try:
+                        filedirdict[parparent].append(par[lensuf:] + os.path.sep)
+                    except KeyError:
+                        filedirdict[parparent] = [par[lensuf:] + os.path.sep]
+                    filedirdict[par] = []
+                    if parparent != repo.root:
+                        newlist.insert(0, parparent)
+
+            for dirname, fnames in filedirdict.iteritems():
+                finalls[i].extend(fnames)
+
+        changestates = zip(states, pycompat.iterbytestr('MAR!?IC'), finalls)
+
+
     for state, char, files in changestates:
         if state in show:
             label = 'status.' + state
diff --git a/tests/test-terse-status.t b/tests/test-terse-status.t
new file mode 100644
--- /dev/null
+++ b/tests/test-terse-status.t
@@ -0,0 +1,73 @@
+  $ hg init repo
+  $ cd repo
+  $ touch a b c
+  $ hg status
+  ? a
+  ? b
+  ? c
+
+This one is not working as its listing .hg as a file, will be fixed when matcher
+will be used
+  $ hg status --terse
+  ? a
+  ? b
+  ? c
+
+  $ mkdir folder
+  $ cd folder
+  $ touch x y z
+  $ hg status
+  ? a
+  ? b
+  ? c
+  ? folder/x
+  ? folder/y
+  ? folder/z
+
+  $ hg status --terse
+  ? folder/
+  ? a
+  ? b
+  ? c
+
+  $ hg add .
+  adding x
+  adding y
+  adding z
+
+  $ hg status
+  A folder/x
+  A folder/y
+  A folder/z
+  ? a
+  ? b
+  ? c
+
+  $ hg status --terse
+  A folder/
+  ? a
+  ? b
+  ? c
+
+  $ mkdir another
+  $ cd another
+  $ touch p q r
+  $ hg status --terse
+  A folder/x
+  A folder/y
+  A folder/z
+  ? folder/another/
+  ? a
+  ? b
+  ? c
+
+  $ hg add .
+  adding p
+  adding q
+  adding r
+
+  $ hg status --terse
+  A folder/
+  ? a
+  ? b
+  ? c


More information about the Mercurial-devel mailing list