Re: D3826: grep : change default behaviour of grep
> @@ -2431,6 +2431,10 @@ > Returns 0 if a match is found, 1 otherwise. > """ > opts = pycompat.byteskwargs(opts) > + > +if len(opts.get('rev')) ==1: > +opts['allfiles'] = True So, `-rA` implies `--allfiles` but `-rA -rB` doesn't? which seems worse than the current situation. And we'll need an option to get back the original behavior. ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D3826: grep: change default behaviour of grep
yuja added a comment. > @@ -2431,6 +2431,10 @@ > > Returns 0 if a match is found, 1 otherwise. > """ > opts = pycompat.byteskwargs(opts) > > + > +if len(opts.get('rev')) ==1: > +opts['allfiles'] = True So, `-rA` implies `--allfiles` but `-rA -rB` doesn't? which seems worse than the current situation. And we'll need an option to get back the original behavior. REPOSITORY rHG Mercurial REVISION DETAIL https://phab.mercurial-scm.org/D3826 To: sangeet259, #hg-reviewers Cc: yuja, mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
Re: D3829: rebase: make dry-run return 1 or 0 according to result
> --- a/hgext/rebase.py > +++ b/hgext/rebase.py > @@ -825,10 +825,13 @@ > **opts) > except error.InMemoryMergeConflictsError: > ui.status(_('hit a merge conflict\n')) > +retcode = 1 > else: > +retcode = 0 > ui.status(_('there will be no conflict, you can rebase\n')) > finally: > _origrebase(ui, repo, abort=True) > +return retcode `retcode` may be undefined depending on the error type occurred in `_origrebase()`. Instead, you can simply return 1 and 0 in the `except` and `else` clauses respectively. ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D3829: rebase: make dry-run return 1 or 0 according to result
yuja added a comment. > - a/hgext/rebase.py +++ b/hgext/rebase.py @@ -825,10 +825,13 @@ **opts) except error.InMemoryMergeConflictsError: ui.status(_('hit a merge conflict\n')) +retcode = 1 else: +retcode = 0 ui.status(_('there will be no conflict, you can rebase\n')) finally: _origrebase(ui, repo, abort=True) +return retcode `retcode` may be undefined depending on the error type occurred in `_origrebase()`. Instead, you can simply return 1 and 0 in the `except` and `else` clauses respectively. REPOSITORY rHG Mercurial REVISION DETAIL https://phab.mercurial-scm.org/D3829 To: khanchi97, #hg-reviewers Cc: yuja, mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D3827: rebase: no need to store backup during dry-run while aborting
yuja added a comment. > - def _prepareabortorcontinue(self, isabort): +def _prepareabortorcontinue(self, isabort, opts={}): Mutable default value should be avoided. It can be `backup=True` since we aren't processing command-level thingy here. And please make sure tests pass before sending out patches. > @@ -828,7 +829,8 @@ > > else: > ui.status(_('there will be no conflict, you can rebase\n')) > finally: > > - _origrebase(ui, repo, abort=True) +opts = {'abort':True, 'no_backup':True} +_origrebase(ui, repo, **opts) Maybe we can refactor the dryrun handling in a way we don't have to pass around the no_backup flag. IIUC, `_origrebase()` is a high-level function which has many parameter/state checks, but what we want is to cancel the in-memory session we've made just before. No user error should occur. > @@ -1588,7 +1590,10 @@ > > 1. Strip from the first rebased revision if rebased: > - repair.strip(repo.ui, repo, strippoints) +if nobackup: + repair.strip(repo.ui, repo, strippoints, backup=False) + else: +repair.strip(repo.ui, repo, strippoints) This can be written as `backup=not nobackup` or `backup=backup`. REPOSITORY rHG Mercurial REVISION DETAIL https://phab.mercurial-scm.org/D3827 To: khanchi97, #hg-reviewers Cc: yuja, mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
Re: D3827: rebase: no need to store backup during dry-run while aborting
> -def _prepareabortorcontinue(self, isabort): > +def _prepareabortorcontinue(self, isabort, opts={}): Mutable default value should be avoided. It can be `backup=True` since we aren't processing command-level thingy here. And please make sure tests pass before sending out patches. > @@ -828,7 +829,8 @@ > else: > ui.status(_('there will be no conflict, you can rebase\n')) > finally: > -_origrebase(ui, repo, abort=True) > +opts = {'abort':True, 'no_backup':True} > +_origrebase(ui, repo, **opts) Maybe we can refactor the dryrun handling in a way we don't have to pass around the no_backup flag. IIUC, `_origrebase()` is a high-level function which has many parameter/state checks, but what we want is to cancel the in-memory session we've made just before. No user error should occur. > @@ -1588,7 +1590,10 @@ > > # Strip from the first rebased revision > if rebased: > -repair.strip(repo.ui, repo, strippoints) > +if nobackup: > +repair.strip(repo.ui, repo, strippoints, backup=False) > +else: > +repair.strip(repo.ui, repo, strippoints) This can be written as `backup=not nobackup` or `backup=backup`. ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
[Bug 5928] New: log command streams entire log after pager closes
https://bz.mercurial-scm.org/show_bug.cgi?id=5928 Bug ID: 5928 Summary: log command streams entire log after pager closes Product: Mercurial Version: 4.6.1 Hardware: PC OS: Windows Status: UNCONFIRMED Severity: bug Priority: wish Component: pager Assignee: bugzi...@mercurial-scm.org Reporter: edwin.br...@gmail.com CC: mercurial-devel@mercurial-scm.org On windows when using pager with hg log mercurial will stream the entire log after terminating the pager. The user must manually terminate the process. This problem has existed on windows for several releases. Ideally, the log command should stop streaming data once the pager is closed. -- You are receiving this mail because: You are on the CC list for the bug. ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D3764: rebase: improve output of --dry-run
khanchi97 updated this revision to Diff 9264. REPOSITORY rHG Mercurial CHANGES SINCE LAST UPDATE https://phab.mercurial-scm.org/D3764?vs=9263=9264 REVISION DETAIL https://phab.mercurial-scm.org/D3764 AFFECTED FILES hgext/rebase.py tests/test-rebase-inmemory.t CHANGE DETAILS diff --git a/tests/test-rebase-inmemory.t b/tests/test-rebase-inmemory.t --- a/tests/test-rebase-inmemory.t +++ b/tests/test-rebase-inmemory.t @@ -208,11 +208,11 @@ Check dryrun gives correct results when there is no conflict in rebasing $ hg rebase -s 2 -d 6 -n + starting dry-run rebase; repository will not be changed rebasing 2:177f92b77385 "c" rebasing 3:055a42cdd887 "d" rebasing 4:e860deea161a "e" - there will be no conflict, you can rebase - rebase aborted + dry-run rebase completed successfully; run without -n/--dry-run to perform this rebase $ hg diff $ hg status @@ -241,11 +241,11 @@ Check dryrun working with --collapse when there is no conflict $ hg rebase -s 2 -d 6 -n --collapse + starting dry-run rebase; repository will not be changed rebasing 2:177f92b77385 "c" rebasing 3:055a42cdd887 "d" rebasing 4:e860deea161a "e" - there will be no conflict, you can rebase - rebase aborted + dry-run rebase completed successfully; run without -n/--dry-run to perform this rebase Check dryrun gives correct results when there is conflict in rebasing Make a conflict: @@ -278,14 +278,14 @@ a $ hg rebase -s 2 -d 7 -n + starting dry-run rebase; repository will not be changed rebasing 2:177f92b77385 "c" rebasing 3:055a42cdd887 "d" rebasing 4:e860deea161a "e" merging e transaction abort! rollback completed hit a merge conflict - rebase aborted $ hg diff $ hg status $ hg log -G --template "{rev}:{short(node)} {person(author)}\n{firstline(desc)} {topic}\n\n" @@ -315,9 +315,9 @@ Check dryrun working with --collapse when there is conflicts $ hg rebase -s 2 -d 7 -n --collapse + starting dry-run rebase; repository will not be changed rebasing 2:177f92b77385 "c" rebasing 3:055a42cdd887 "d" rebasing 4:e860deea161a "e" merging e hit a merge conflict - rebase aborted diff --git a/hgext/rebase.py b/hgext/rebase.py --- a/hgext/rebase.py +++ b/hgext/rebase.py @@ -341,9 +341,11 @@ hint = _('use "hg rebase --abort" to clear broken state') raise error.Abort(msg, hint=hint) if isabort: +suppwarns = opts.get(r'dry_run') nobackup = opts.get(r'no_backup') return abort(self.repo, self.originalwd, self.destmap, self.state, - activebookmark=self.activebookmark, nobackup=nobackup) + activebookmark=self.activebookmark, nobackup=nobackup, + suppwarns=suppwarns) def _preparenewrebase(self, destmap): if not destmap: @@ -819,17 +821,19 @@ opts[r'dest'] = '_destautoorphanrebase(SRC)' if dryrun: +ui.status(_('starting dry-run rebase; repository will not be changed\n')) try: overrides = {('rebase', 'singletransaction'): True} with ui.configoverride(overrides, 'rebase'): _origrebase(ui, repo, inmemory=True, leaveunfinished=True, **opts) except error.InMemoryMergeConflictsError: ui.status(_('hit a merge conflict\n')) else: -ui.status(_('there will be no conflict, you can rebase\n')) +ui.status(_('dry-run rebase completed successfully; run without ' +'-n/--dry-run to perform this rebase\n')) finally: -opts = {'abort':True, 'no_backup':True} +opts = {'abort':True, 'no_backup':True, 'dry_run':True} _origrebase(ui, repo, **opts) elif inmemory: try: @@ -1545,7 +1549,8 @@ return False -def abort(repo, originalwd, destmap, state, activebookmark=None, nobackup=False): +def abort(repo, originalwd, destmap, state, activebookmark=None, nobackup=False, + suppwarns=False): '''Restore the repository to its original state. Additional args: activebookmark: the name of the bookmark that should be active after the @@ -1601,7 +1606,8 @@ finally: clearstatus(repo) clearcollapsemsg(repo) -repo.ui.warn(_('rebase aborted\n')) +if not suppwarns: +repo.ui.warn(_('rebase aborted\n')) return 0 def sortsource(destmap): To: khanchi97, #hg-reviewers Cc: indygreg, pulkit, mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D3764: rebase: improve output of --dry-run
khanchi97 updated this revision to Diff 9263. REPOSITORY rHG Mercurial CHANGES SINCE LAST UPDATE https://phab.mercurial-scm.org/D3764?vs=9259=9263 REVISION DETAIL https://phab.mercurial-scm.org/D3764 AFFECTED FILES hgext/rebase.py tests/test-rebase-inmemory.t CHANGE DETAILS diff --git a/tests/test-rebase-inmemory.t b/tests/test-rebase-inmemory.t --- a/tests/test-rebase-inmemory.t +++ b/tests/test-rebase-inmemory.t @@ -208,11 +208,11 @@ Check dryrun gives correct results when there is no conflict in rebasing $ hg rebase -s 2 -d 6 -n + starting dry-run rebase; repository will not be changed rebasing 2:177f92b77385 "c" rebasing 3:055a42cdd887 "d" rebasing 4:e860deea161a "e" - there will be no conflict, you can rebase - rebase aborted + dry-run rebase completed successfully; run without -n/--dry-run to perform this rebase $ hg diff $ hg status @@ -241,11 +241,11 @@ Check dryrun working with --collapse when there is no conflict $ hg rebase -s 2 -d 6 -n --collapse + starting dry-run rebase; repository will not be changed rebasing 2:177f92b77385 "c" rebasing 3:055a42cdd887 "d" rebasing 4:e860deea161a "e" - there will be no conflict, you can rebase - rebase aborted + dry-run rebase completed successfully; run without -n/--dry-run to perform this rebase Check dryrun gives correct results when there is conflict in rebasing Make a conflict: @@ -278,14 +278,14 @@ a $ hg rebase -s 2 -d 7 -n + starting dry-run rebase; repository will not be changed rebasing 2:177f92b77385 "c" rebasing 3:055a42cdd887 "d" rebasing 4:e860deea161a "e" merging e transaction abort! rollback completed hit a merge conflict - rebase aborted $ hg diff $ hg status $ hg log -G --template "{rev}:{short(node)} {person(author)}\n{firstline(desc)} {topic}\n\n" @@ -315,9 +315,9 @@ Check dryrun working with --collapse when there is conflicts $ hg rebase -s 2 -d 7 -n --collapse + starting dry-run rebase; repository will not be changed rebasing 2:177f92b77385 "c" rebasing 3:055a42cdd887 "d" rebasing 4:e860deea161a "e" merging e hit a merge conflict - rebase aborted diff --git a/hgext/rebase.py b/hgext/rebase.py --- a/hgext/rebase.py +++ b/hgext/rebase.py @@ -341,9 +341,11 @@ hint = _('use "hg rebase --abort" to clear broken state') raise error.Abort(msg, hint=hint) if isabort: +suppwarns = opts.get(r'dry_run') nobackup = opts.get(r'no_backup') return abort(self.repo, self.originalwd, self.destmap, self.state, - activebookmark=self.activebookmark, nobackup=nobackup) + activebookmark=self.activebookmark, nobackup=nobackup, + suppwarns=suppwarns) def _preparenewrebase(self, destmap): if not destmap: @@ -819,17 +821,19 @@ opts[r'dest'] = '_destautoorphanrebase(SRC)' if dryrun: +ui.status(_('starting dry-run rebase; repository will not be changed\n')) try: overrides = {('rebase', 'singletransaction'): True} with ui.configoverride(overrides, 'rebase'): _origrebase(ui, repo, inmemory=True, leaveunfinished=True, **opts) except error.InMemoryMergeConflictsError: ui.status(_('hit a merge conflict\n')) else: -ui.status(_('there will be no conflict, you can rebase\n')) +ui.status(_('dry-run rebase completed successfully; run without ' +'-n/--dry-run to perform this rebase\n')) finally: -opts = {'abort':True, 'no_backup':True} +opts = {'abort':True, 'no_backup':True, 'dry_run':True} _origrebase(ui, repo, **opts) elif inmemory: try: @@ -1545,7 +1549,8 @@ return False -def abort(repo, originalwd, destmap, state, activebookmark=None, nobackup=False): +def abort(repo, originalwd, destmap, state, activebookmark=None, nobackup=False, + suppwarning=False): '''Restore the repository to its original state. Additional args: activebookmark: the name of the bookmark that should be active after the @@ -1601,7 +1606,8 @@ finally: clearstatus(repo) clearcollapsemsg(repo) -repo.ui.warn(_('rebase aborted\n')) +if not suppwarning: +repo.ui.warn(_('rebase aborted\n')) return 0 def sortsource(destmap): To: khanchi97, #hg-reviewers Cc: indygreg, pulkit, mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D3827: rebase: no need to store backup during dry-run while aborting
khanchi97 updated this revision to Diff 9262. REPOSITORY rHG Mercurial CHANGES SINCE LAST UPDATE https://phab.mercurial-scm.org/D3827?vs=9260=9262 REVISION DETAIL https://phab.mercurial-scm.org/D3827 AFFECTED FILES hgext/rebase.py tests/test-rebase-inmemory.t CHANGE DETAILS diff --git a/tests/test-rebase-inmemory.t b/tests/test-rebase-inmemory.t --- a/tests/test-rebase-inmemory.t +++ b/tests/test-rebase-inmemory.t @@ -212,7 +212,6 @@ rebasing 3:055a42cdd887 "d" rebasing 4:e860deea161a "e" there will be no conflict, you can rebase - saved backup bundle to $TESTTMP/repo1/repo2/skrepo/.hg/strip-backup/c83b1da5b1ae-f1e0beb9-backup.hg rebase aborted $ hg diff diff --git a/hgext/rebase.py b/hgext/rebase.py --- a/hgext/rebase.py +++ b/hgext/rebase.py @@ -325,7 +325,7 @@ skippedset.update(obsoleteextinctsuccessors) _checkobsrebase(self.repo, self.ui, obsoleteset, skippedset) -def _prepareabortorcontinue(self, isabort): +def _prepareabortorcontinue(self, isabort, opts={}): try: self.restorestatus() self.collapsemsg = restorecollapsemsg(self.repo, isabort) @@ -341,8 +341,9 @@ hint = _('use "hg rebase --abort" to clear broken state') raise error.Abort(msg, hint=hint) if isabort: -return abort(self.repo, self.originalwd, self.destmap, - self.state, activebookmark=self.activebookmark) +nobackup = opts.get(r'no_backup') +return abort(self.repo, self.originalwd, self.destmap, self.state, + activebookmark=self.activebookmark, nobackup=nobackup) def _preparenewrebase(self, destmap): if not destmap: @@ -828,7 +829,8 @@ else: ui.status(_('there will be no conflict, you can rebase\n')) finally: -_origrebase(ui, repo, abort=True) +opts = {'abort':True, 'no_backup':True} +_origrebase(ui, repo, **opts) elif inmemory: try: # in-memory merge doesn't support conflicts, so if we hit any, abort @@ -889,7 +891,7 @@ ms = mergemod.mergestate.read(repo) mergeutil.checkunresolved(ms) -retcode = rbsrt._prepareabortorcontinue(abortf) +retcode = rbsrt._prepareabortorcontinue(abortf, opts=opts) if retcode is not None: return retcode else: @@ -1543,7 +1545,7 @@ return False -def abort(repo, originalwd, destmap, state, activebookmark=None): +def abort(repo, originalwd, destmap, state, activebookmark=None, nobackup=False): '''Restore the repository to its original state. Additional args: activebookmark: the name of the bookmark that should be active after the @@ -1588,7 +1590,10 @@ # Strip from the first rebased revision if rebased: -repair.strip(repo.ui, repo, strippoints) +if nobackup: +repair.strip(repo.ui, repo, strippoints, backup=False) +else: +repair.strip(repo.ui, repo, strippoints) if activebookmark and activebookmark in repo._bookmarks: bookmarks.activate(repo, activebookmark) To: khanchi97, #hg-reviewers Cc: mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
[PATCH 1 of 4] templater: fix truth testing of integer 0 taken from a list/dict
# HG changeset patch # User Yuya Nishihara # Date 1529219438 -32400 # Sun Jun 17 16:10:38 2018 +0900 # Node ID 720fc7b592ef6dd5dc11a7ec48a715ee39c1006a # Parent 36edfbac7281c731b1aed8e73555b22c2ccb96c0 templater: fix truth testing of integer 0 taken from a list/dict Broken at f9c426385853. bool(python_value) shouldn't be used here since an integer 0 has to be truthy for backward compatibility. diff --git a/mercurial/templateutil.py b/mercurial/templateutil.py --- a/mercurial/templateutil.py +++ b/mercurial/templateutil.py @@ -350,7 +350,8 @@ class hybriditem(mappable, wrapped): return gen def tobool(self, context, mapping): -return bool(self.tovalue(context, mapping)) +w = makewrapped(context, mapping, self._value) +return w.tobool(context, mapping) def tovalue(self, context, mapping): return _unthunk(context, mapping, self._value) diff --git a/tests/test-template-functions.t b/tests/test-template-functions.t --- a/tests/test-template-functions.t +++ b/tests/test-template-functions.t @@ -932,6 +932,8 @@ Test boolean expression/literal passed t rev 0 is True $ hg log -r 0 -T '{if(0, "literal 0 is True as well")}\n' literal 0 is True as well + $ hg log -r 0 -T '{if(min(revset(r"0")), "0 of hybriditem is also True")}\n' + 0 of hybriditem is also True $ hg log -r 0 -T '{if("", "", "empty string is False")}\n' empty string is False $ hg log -r 0 -T '{if(revset(r"0 - 0"), "", "empty list is False")}\n' ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
[PATCH 4 of 4] show: use filter() function to strip "tip" tag
# HG changeset patch # User Yuya Nishihara # Date 1528986171 -32400 # Thu Jun 14 23:22:51 2018 +0900 # Node ID 7d4982dc9d52624ebd62f249639ca596101415ca # Parent f2d42f1933ce7e28647f2b834c86de3369fbbe00 show: use filter() function to strip "tip" tag Before, an empty tag "" was inserted in place of "tip", resulting in double spaces. diff --git a/mercurial/templates/map-cmdline.show b/mercurial/templates/map-cmdline.show --- a/mercurial/templates/map-cmdline.show +++ b/mercurial/templates/map-cmdline.show @@ -15,8 +15,11 @@ cset_shortnode = '{labelcset(shortest(no # Treat branch and tags specially so we don't display "default" or "tip" cset_namespace = '{ifeq(namespace, "branches", names_branches, ifeq(namespace, "tags", names_tags, names_others))}' names_branches = '{ifeq(branch, "default", "", " ({label('log.{colorname}', branch)})")}' -names_tags = '{if(stringify(names % "{ifeq(name, 'tip', '', name)}"), - " ({label('log.{colorname}', join(names % "{ifeq(name, 'tip', '', name)}", ' '))})")}' +names_tags = '{if(filter_tags(names), + " ({label('log.{colorname}', join(filter_tags(names), ' '))})")}' names_others = '{if(names, " ({label('log.{colorname}', join(names, ' '))})")}' cset_shortdesc = '{label("log.description", desc|firstline)}' + +[templatealias] +filter_tags(names) = filter(names, ifeq(name, 'tip', '', name)) ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
[PATCH 2 of 4] templater: introduce filter() function to remove empty items from list
# HG changeset patch # User Yuya Nishihara # Date 1528983206 -32400 # Thu Jun 14 22:33:26 2018 +0900 # Node ID f14965009644ab63cbe1990081493e8d490a30eb # Parent 720fc7b592ef6dd5dc11a7ec48a715ee39c1006a templater: introduce filter() function to remove empty items from list The primary use case is to filter out "tip" from a list of tags. diff --git a/mercurial/hgweb/webutil.py b/mercurial/hgweb/webutil.py --- a/mercurial/hgweb/webutil.py +++ b/mercurial/hgweb/webutil.py @@ -727,6 +727,10 @@ class sessionvars(templateutil.wrapped): def getmax(self, context, mapping): raise error.ParseError(_('not comparable')) +def filter(self, context, mapping, select): +# implement if necessary +raise error.ParseError(_('not filterable')) + def itermaps(self, context): separator = self._start for key, value in sorted(self._vars.iteritems()): diff --git a/mercurial/templatefuncs.py b/mercurial/templatefuncs.py --- a/mercurial/templatefuncs.py +++ b/mercurial/templatefuncs.py @@ -166,6 +166,17 @@ def fill(context, mapping, args): return templatefilters.fill(text, width, initindent, hangindent) +@templatefunc('filter(iterable)') +def filter_(context, mapping, args): +"""Remove empty elements from a list or a dict.""" +if len(args) != 1: +# i18n: "filter" is a keyword +raise error.ParseError(_("filter expects one argument")) +iterable = evalwrapped(context, mapping, args[0]) +def select(w): +return w.tobool(context, mapping) +return iterable.filter(context, mapping, select) + @templatefunc('formatnode(node)', requires={'ui'}) def formatnode(context, mapping, args): """Obtain the preferred form of a changeset hash. (DEPRECATED)""" diff --git a/mercurial/templateutil.py b/mercurial/templateutil.py --- a/mercurial/templateutil.py +++ b/mercurial/templateutil.py @@ -63,6 +63,14 @@ class wrapped(object): value depending on the self type""" @abc.abstractmethod +def filter(self, context, mapping, select): +"""Return new container of the same type which includes only the +selected elements + +select() takes each item as a wrapped object and returns True/False. +""" + +@abc.abstractmethod def itermaps(self, context): """Yield each template mapping""" @@ -130,6 +138,10 @@ class wrappedbytes(wrapped): raise error.ParseError(_('empty string')) return func(pycompat.iterbytestr(self._value)) +def filter(self, context, mapping, select): +raise error.ParseError(_('%r is not filterable') + % pycompat.bytestr(self._value)) + def itermaps(self, context): raise error.ParseError(_('%r is not iterable of mappings') % pycompat.bytestr(self._value)) @@ -164,6 +176,9 @@ class wrappedvalue(wrapped): def getmax(self, context, mapping): raise error.ParseError(_("%r is not iterable") % self._value) +def filter(self, context, mapping, select): +raise error.ParseError(_("%r is not iterable") % self._value) + def itermaps(self, context): raise error.ParseError(_('%r is not iterable of mappings') % self._value) @@ -208,6 +223,9 @@ class date(mappable, wrapped): def getmax(self, context, mapping): raise error.ParseError(_('date is not iterable')) +def filter(self, context, mapping, select): +raise error.ParseError(_('date is not iterable')) + def join(self, context, mapping, sep): raise error.ParseError(_("date is not iterable")) @@ -273,6 +291,14 @@ class hybrid(wrapped): return val return hybriditem(None, key, val, self._makemap) +def filter(self, context, mapping, select): +if util.safehasattr(self._values, 'get'): +values = {k: v for k, v in self._values.iteritems() + if select(self._wrapvalue(k, v))} +else: +values = [v for v in self._values if select(self._wrapvalue(v, v))] +return hybrid(None, values, self._makemap, self._joinfmt, self._keytype) + def itermaps(self, context): makemap = self._makemap for x in self._values: @@ -336,6 +362,10 @@ class hybriditem(mappable, wrapped): w = makewrapped(context, mapping, self._value) return w.getmax(context, mapping) +def filter(self, context, mapping, select): +w = makewrapped(context, mapping, self._value) +return w.filter(context, mapping, select) + def join(self, context, mapping, sep): w = makewrapped(context, mapping, self._value) return w.join(context, mapping, sep) @@ -384,6 +414,9 @@ class _mappingsequence(wrapped): def getmax(self, context, mapping): raise error.ParseError(_('not comparable')) +def filter(self, context, mapping, select): +raise error.ParseError(_('not
[PATCH 3 of 4] templater: extend filter() to accept template expression for emptiness test
# HG changeset patch # User Yuya Nishihara # Date 1528985414 -32400 # Thu Jun 14 23:10:14 2018 +0900 # Node ID f2d42f1933ce7e28647f2b834c86de3369fbbe00 # Parent f14965009644ab63cbe1990081493e8d490a30eb templater: extend filter() to accept template expression for emptiness test This utilizes the pass-by-name nature of template arguments. diff --git a/mercurial/templatefuncs.py b/mercurial/templatefuncs.py --- a/mercurial/templatefuncs.py +++ b/mercurial/templatefuncs.py @@ -166,15 +166,23 @@ def fill(context, mapping, args): return templatefilters.fill(text, width, initindent, hangindent) -@templatefunc('filter(iterable)') +@templatefunc('filter(iterable[, expr])') def filter_(context, mapping, args): -"""Remove empty elements from a list or a dict.""" -if len(args) != 1: +"""Remove empty elements from a list or a dict. If expr specified, it's +applied to each element to test emptiness.""" +if not (1 <= len(args) <= 2): # i18n: "filter" is a keyword -raise error.ParseError(_("filter expects one argument")) +raise error.ParseError(_("filter expects one or two arguments")) iterable = evalwrapped(context, mapping, args[0]) -def select(w): -return w.tobool(context, mapping) +if len(args) == 1: +def select(w): +return w.tobool(context, mapping) +else: +def select(w): +if not isinstance(w, templateutil.mappable): +raise error.ParseError(_("not filterable by expression")) +lm = context.overlaymap(mapping, w.tomap(context)) +return evalboolean(context, lm, args[1]) return iterable.filter(context, mapping, select) @templatefunc('formatnode(node)', requires={'ui'}) diff --git a/mercurial/templateutil.py b/mercurial/templateutil.py --- a/mercurial/templateutil.py +++ b/mercurial/templateutil.py @@ -415,6 +415,7 @@ class _mappingsequence(wrapped): raise error.ParseError(_('not comparable')) def filter(self, context, mapping, select): +# implement if necessary; we'll need a wrapped type for a mapping dict raise error.ParseError(_('not filterable without template')) def join(self, context, mapping, sep): diff --git a/tests/test-template-functions.t b/tests/test-template-functions.t --- a/tests/test-template-functions.t +++ b/tests/test-template-functions.t @@ -449,6 +449,13 @@ Test filter() empty values: $ hg log -R a -r 0 -T '{filter(revset("0:2"))}\n' 0 1 2 +Test filter() by expression: + + $ hg log -R a -r 1 -T '{filter(desc|splitlines, ifcontains("1", line, "t"))}\n' + other 1 + $ hg log -R a -r 0 -T '{filter(dict(a=0, b=1), ifeq(key, "b", "t"))}\n' + b=1 + Test filter() shouldn't crash: $ hg log -R a -r 0 -T '{filter(extras)}\n' @@ -459,7 +466,7 @@ Test filter() shouldn't crash: Test filter() unsupported arguments: $ hg log -R a -r 0 -T '{filter()}\n' - hg: parse error: filter expects one argument + hg: parse error: filter expects one or two arguments [255] $ hg log -R a -r 0 -T '{filter(date)}\n' hg: parse error: date is not iterable @@ -476,6 +483,9 @@ Test filter() unsupported arguments: $ hg log -R a -r 0 -T '{filter(succsandmarkers)}\n' hg: parse error: not filterable without template [255] + $ hg log -R a -r 0 -T '{filter(desc|splitlines % "{line}", "")}\n' + hg: parse error: not filterable by expression + [255] Test manifest/get() can be join()-ed as string, though it's silly: ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel