Mercurial > public > mercurial-scm > hg-stable
comparison mercurial/ui.py @ 31695:2d11d278279a
ui: defer setting pager related properties until the pager has spawned
When --pager=on is given, dispatch.py spawns a pager before setting up color.
If the pager failed to launch, ui.pageractive was left set to True, so color
configured itself based on 'color.pagermode'. A typical MSYS setting would be
'color.mode=auto, color.pagermode=ansi'. In the failure case, this would print
a warning, disable the pager, and then print the raw ANSI codes to the terminal.
Care needs to be taken, because it appears that leaving ui.pageractive=True was
the only thing that prevented an attempt at running the pager again from inside
the command. This results in a double warning message, so pager is simply
disabled on failure.
The ui config settings didn't need to be moved to fix this, but it seemed like
the right thing to do for consistency.
author | Matt Harbison <matt_harbison@yahoo.com> |
---|---|
date | Sat, 25 Mar 2017 21:12:00 -0400 |
parents | c5fe0c7dad94 |
children | c3ca0ad8ab9c |
comparison
equal
deleted
inserted
replaced
31694:57a22f699179 | 31695:2d11d278279a |
---|---|
854 if not pagercmd: | 854 if not pagercmd: |
855 return | 855 return |
856 | 856 |
857 self.debug('starting pager for command %r\n' % command) | 857 self.debug('starting pager for command %r\n' % command) |
858 self.flush() | 858 self.flush() |
859 self.pageractive = True | 859 |
860 # Preserve the formatted-ness of the UI. This is important | 860 wasformatted = self.formatted() |
861 # because we mess with stdout, which might confuse | |
862 # auto-detection of things being formatted. | |
863 self.setconfig('ui', 'formatted', self.formatted(), 'pager') | |
864 self.setconfig('ui', 'interactive', False, 'pager') | |
865 if util.safehasattr(signal, "SIGPIPE"): | 861 if util.safehasattr(signal, "SIGPIPE"): |
866 signal.signal(signal.SIGPIPE, _catchterm) | 862 signal.signal(signal.SIGPIPE, _catchterm) |
867 self._runpager(pagercmd) | 863 if self._runpager(pagercmd): |
864 self.pageractive = True | |
865 # Preserve the formatted-ness of the UI. This is important | |
866 # because we mess with stdout, which might confuse | |
867 # auto-detection of things being formatted. | |
868 self.setconfig('ui', 'formatted', wasformatted, 'pager') | |
869 self.setconfig('ui', 'interactive', False, 'pager') | |
870 else: | |
871 # If the pager can't be spawned in dispatch when --pager=on is | |
872 # given, don't try again when the command runs, to avoid a duplicate | |
873 # warning about a missing pager command. | |
874 self.disablepager() | |
868 | 875 |
869 def _runpager(self, command): | 876 def _runpager(self, command): |
870 """Actually start the pager and set up file descriptors. | 877 """Actually start the pager and set up file descriptors. |
871 | 878 |
872 This is separate in part so that extensions (like chg) can | 879 This is separate in part so that extensions (like chg) can |
873 override how a pager is invoked. | 880 override how a pager is invoked. |
874 """ | 881 """ |
875 if command == 'cat': | 882 if command == 'cat': |
876 # Save ourselves some work. | 883 # Save ourselves some work. |
877 return | 884 return False |
878 # If the command doesn't contain any of these characters, we | 885 # If the command doesn't contain any of these characters, we |
879 # assume it's a binary and exec it directly. This means for | 886 # assume it's a binary and exec it directly. This means for |
880 # simple pager command configurations, we can degrade | 887 # simple pager command configurations, we can degrade |
881 # gracefully and tell the user about their broken pager. | 888 # gracefully and tell the user about their broken pager. |
882 shell = any(c in command for c in "|&;<>()$`\\\"' \t\n*?[#~=%") | 889 shell = any(c in command for c in "|&;<>()$`\\\"' \t\n*?[#~=%") |
889 # determine which one to use. | 896 # determine which one to use. |
890 fullcmd = util.findexe(command) | 897 fullcmd = util.findexe(command) |
891 if not fullcmd: | 898 if not fullcmd: |
892 self.warn(_("missing pager command '%s', skipping pager\n") | 899 self.warn(_("missing pager command '%s', skipping pager\n") |
893 % command) | 900 % command) |
894 return | 901 return False |
895 | 902 |
896 command = fullcmd | 903 command = fullcmd |
897 | 904 |
898 try: | 905 try: |
899 pager = subprocess.Popen( | 906 pager = subprocess.Popen( |
902 stdout=util.stdout, stderr=util.stderr) | 909 stdout=util.stdout, stderr=util.stderr) |
903 except OSError as e: | 910 except OSError as e: |
904 if e.errno == errno.ENOENT and not shell: | 911 if e.errno == errno.ENOENT and not shell: |
905 self.warn(_("missing pager command '%s', skipping pager\n") | 912 self.warn(_("missing pager command '%s', skipping pager\n") |
906 % command) | 913 % command) |
907 return | 914 return False |
908 raise | 915 raise |
909 | 916 |
910 # back up original file descriptors | 917 # back up original file descriptors |
911 stdoutfd = os.dup(util.stdout.fileno()) | 918 stdoutfd = os.dup(util.stdout.fileno()) |
912 stderrfd = os.dup(util.stderr.fileno()) | 919 stderrfd = os.dup(util.stderr.fileno()) |
922 # restore original fds, closing pager.stdin copies in the process | 929 # restore original fds, closing pager.stdin copies in the process |
923 os.dup2(stdoutfd, util.stdout.fileno()) | 930 os.dup2(stdoutfd, util.stdout.fileno()) |
924 os.dup2(stderrfd, util.stderr.fileno()) | 931 os.dup2(stderrfd, util.stderr.fileno()) |
925 pager.stdin.close() | 932 pager.stdin.close() |
926 pager.wait() | 933 pager.wait() |
934 | |
935 return True | |
927 | 936 |
928 def interface(self, feature): | 937 def interface(self, feature): |
929 """what interface to use for interactive console features? | 938 """what interface to use for interactive console features? |
930 | 939 |
931 The interface is controlled by the value of `ui.interface` but also by | 940 The interface is controlled by the value of `ui.interface` but also by |