From ce3564bf8e28d1d8eb74c6c2f768692d13e035c2 Mon Sep 17 00:00:00 2001 From: Adam Harvey Date: Thu, 20 Aug 2020 12:45:02 -0700 Subject: [PATCH] output: improve Windows console handling The new output code is pretty nifty in Windows Terminal, but users still using the legacy console with cmd.exe or PowerShell are going to get pretty ugly output, since the escape codes aren't handled by default. This adds support for enabling virtual terminal processing, which makes things pretty. (Well, prettier, anyway. Note also #273.) --- CHANGELOG.md | 6 ++++++ go.mod | 2 +- internal/output/output.go | 13 ++++++++++- internal/output/output_windows.go | 36 +++++++++++++++++++++++++++++++ 4 files changed, 55 insertions(+), 2 deletions(-) create mode 100644 internal/output/output_windows.go diff --git a/CHANGELOG.md b/CHANGELOG.md index 0bc199fedf..fd402d9b89 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,12 @@ All notable changes to `src-cli` are documented in this file. +## Unreleased changes + +### Fixed + +- `src campaigns` output has been improved in the Windows console. [#274](https://github.com/sourcegraph/src-cli/pull/274) + ## 3.18.0 ### Added diff --git a/go.mod b/go.mod index 0819c64044..092cdca3a8 100644 --- a/go.mod +++ b/go.mod @@ -22,7 +22,7 @@ require ( github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect github.com/xeipuuv/gojsonschema v1.2.0 golang.org/x/net v0.0.0-20200625001655-4c5254603344 - golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4 // indirect + golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4 gopkg.in/yaml.v2 v2.3.0 jaytaylor.com/html2text v0.0.0-20200412013138-3577fbdbcff7 ) diff --git a/internal/output/output.go b/internal/output/output.go index df1bcda38b..b3115ce45f 100644 --- a/internal/output/output.go +++ b/internal/output/output.go @@ -47,13 +47,24 @@ type OutputOpts struct { Verbose bool } +// newOutputPlatformQuirks provides a way for conditionally compiled code to +// hook into NewOutput to perform any required setup. +var newOutputPlatformQuirks func(o *Output) error + func NewOutput(w io.Writer, opts OutputOpts) *Output { caps := detectCapabilities() if opts.ForceColor { caps.Color = true } - return &Output{caps: caps, opts: opts, w: w} + o := &Output{caps: caps, opts: opts, w: w} + if newOutputPlatformQuirks != nil { + if err := newOutputPlatformQuirks(o); err != nil { + o.Verbosef("Error handling platform quirks: %v", err) + } + } + + return o } func (o *Output) Verbose(s string) { diff --git a/internal/output/output_windows.go b/internal/output/output_windows.go new file mode 100644 index 0000000000..d55647fbc0 --- /dev/null +++ b/internal/output/output_windows.go @@ -0,0 +1,36 @@ +package output + +import ( + "github.com/hashicorp/go-multierror" + "golang.org/x/sys/windows" +) + +func init() { + newOutputPlatformQuirks = func(o *Output) error { + var errs *multierror.Error + + if err := setConsoleMode(windows.Stdout, windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING); err != nil { + errs = multierror.Append(errs, err) + } + if err := setConsoleMode(windows.Stderr, windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING); err != nil { + errs = multierror.Append(errs, err) + } + + return errs.ErrorOrNil() + } +} + +func setConsoleMode(handle windows.Handle, flags uint32) error { + // This is shamelessly lifted from gitlab-runner, specifically + // https://gitlab.com/gitlab-org/gitlab-runner/blob/f8d87f1e3e3af1cc8aadcea3e40bbb069eee72ef/helpers/cli/init_cli_windows.go + + // First we have to get the current console mode so we can add the desired + // flags. + var mode uint32 + if err := windows.GetConsoleMode(handle, &mode); err != nil { + return err + } + + // Now we can set the console mode. + return windows.SetConsoleMode(handle, mode|flags) +}