Loading ui/terminal/smart_status.go +55 −11 Original line number Diff line number Diff line Loading @@ -17,8 +17,11 @@ package terminal import ( "fmt" "io" "os" "os/signal" "strings" "sync" "syscall" "android/soong/ui/status" ) Loading @@ -30,18 +33,30 @@ type smartStatusOutput struct { lock sync.Mutex haveBlankLine bool termWidth int sigwinch chan os.Signal sigwinchHandled chan bool } // NewSmartStatusOutput returns a StatusOutput that represents the // current build status similarly to Ninja's built-in terminal // output. func NewSmartStatusOutput(w io.Writer, formatter formatter) status.StatusOutput { return &smartStatusOutput{ s := &smartStatusOutput{ writer: w, formatter: formatter, haveBlankLine: true, sigwinch: make(chan os.Signal), } s.updateTermSize() s.startSigwinch() return s } func (s *smartStatusOutput) Message(level status.MsgLevel, message string) { Loading Loading @@ -101,6 +116,8 @@ func (s *smartStatusOutput) Flush() { s.lock.Lock() defer s.lock.Unlock() s.stopSigwinch() s.requestLine() } Loading Loading @@ -137,16 +154,8 @@ func (s *smartStatusOutput) statusLine(str string) { // Limit line width to the terminal width, otherwise we'll wrap onto // another line and we won't delete the previous line. // // Run this on every line in case the window has been resized while // we're printing. This could be optimized to only re-run when we get // SIGWINCH if it ever becomes too time consuming. if max, ok := termWidth(s.writer); ok { if len(str) > max { // TODO: Just do a max. Ninja elides the middle, but that's // more complicated and these lines aren't that important. str = str[:max] } if s.termWidth > 0 { str = s.elide(str) } // Move to the beginning on the line, turn on bold, print the output, Loading @@ -156,3 +165,38 @@ func (s *smartStatusOutput) statusLine(str string) { fmt.Fprint(s.writer, start, str, end) s.haveBlankLine = false } func (s *smartStatusOutput) elide(str string) string { if len(str) > s.termWidth { // TODO: Just do a max. Ninja elides the middle, but that's // more complicated and these lines aren't that important. str = str[:s.termWidth] } return str } func (s *smartStatusOutput) startSigwinch() { signal.Notify(s.sigwinch, syscall.SIGWINCH) go func() { for _ = range s.sigwinch { s.lock.Lock() s.updateTermSize() s.lock.Unlock() if s.sigwinchHandled != nil { s.sigwinchHandled <- true } } }() } func (s *smartStatusOutput) stopSigwinch() { signal.Stop(s.sigwinch) close(s.sigwinch) } func (s *smartStatusOutput) updateTermSize() { if w, ok := termWidth(s.writer); ok { s.termWidth = w } } ui/terminal/status_test.go +6 −0 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ package terminal import ( "bytes" "fmt" "syscall" "testing" "android/soong/ui/status" Loading Loading @@ -252,6 +253,8 @@ func actionWithOuptutWithAnsiCodes(stat status.StatusOutput) { func TestSmartStatusOutputWidthChange(t *testing.T) { smart := &fakeSmartTerminal{termWidth: 40} stat := NewStatusOutput(smart, "", false) smartStat := stat.(*smartStatusOutput) smartStat.sigwinchHandled = make(chan bool) runner := newRunner(stat, 2) Loading @@ -260,6 +263,9 @@ func TestSmartStatusOutputWidthChange(t *testing.T) { runner.startAction(action) smart.termWidth = 30 // Fake a SIGWINCH smartStat.sigwinch <- syscall.SIGWINCH <-smartStat.sigwinchHandled runner.finishAction(result) stat.Flush() Loading Loading
ui/terminal/smart_status.go +55 −11 Original line number Diff line number Diff line Loading @@ -17,8 +17,11 @@ package terminal import ( "fmt" "io" "os" "os/signal" "strings" "sync" "syscall" "android/soong/ui/status" ) Loading @@ -30,18 +33,30 @@ type smartStatusOutput struct { lock sync.Mutex haveBlankLine bool termWidth int sigwinch chan os.Signal sigwinchHandled chan bool } // NewSmartStatusOutput returns a StatusOutput that represents the // current build status similarly to Ninja's built-in terminal // output. func NewSmartStatusOutput(w io.Writer, formatter formatter) status.StatusOutput { return &smartStatusOutput{ s := &smartStatusOutput{ writer: w, formatter: formatter, haveBlankLine: true, sigwinch: make(chan os.Signal), } s.updateTermSize() s.startSigwinch() return s } func (s *smartStatusOutput) Message(level status.MsgLevel, message string) { Loading Loading @@ -101,6 +116,8 @@ func (s *smartStatusOutput) Flush() { s.lock.Lock() defer s.lock.Unlock() s.stopSigwinch() s.requestLine() } Loading Loading @@ -137,16 +154,8 @@ func (s *smartStatusOutput) statusLine(str string) { // Limit line width to the terminal width, otherwise we'll wrap onto // another line and we won't delete the previous line. // // Run this on every line in case the window has been resized while // we're printing. This could be optimized to only re-run when we get // SIGWINCH if it ever becomes too time consuming. if max, ok := termWidth(s.writer); ok { if len(str) > max { // TODO: Just do a max. Ninja elides the middle, but that's // more complicated and these lines aren't that important. str = str[:max] } if s.termWidth > 0 { str = s.elide(str) } // Move to the beginning on the line, turn on bold, print the output, Loading @@ -156,3 +165,38 @@ func (s *smartStatusOutput) statusLine(str string) { fmt.Fprint(s.writer, start, str, end) s.haveBlankLine = false } func (s *smartStatusOutput) elide(str string) string { if len(str) > s.termWidth { // TODO: Just do a max. Ninja elides the middle, but that's // more complicated and these lines aren't that important. str = str[:s.termWidth] } return str } func (s *smartStatusOutput) startSigwinch() { signal.Notify(s.sigwinch, syscall.SIGWINCH) go func() { for _ = range s.sigwinch { s.lock.Lock() s.updateTermSize() s.lock.Unlock() if s.sigwinchHandled != nil { s.sigwinchHandled <- true } } }() } func (s *smartStatusOutput) stopSigwinch() { signal.Stop(s.sigwinch) close(s.sigwinch) } func (s *smartStatusOutput) updateTermSize() { if w, ok := termWidth(s.writer); ok { s.termWidth = w } }
ui/terminal/status_test.go +6 −0 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ package terminal import ( "bytes" "fmt" "syscall" "testing" "android/soong/ui/status" Loading Loading @@ -252,6 +253,8 @@ func actionWithOuptutWithAnsiCodes(stat status.StatusOutput) { func TestSmartStatusOutputWidthChange(t *testing.T) { smart := &fakeSmartTerminal{termWidth: 40} stat := NewStatusOutput(smart, "", false) smartStat := stat.(*smartStatusOutput) smartStat.sigwinchHandled = make(chan bool) runner := newRunner(stat, 2) Loading @@ -260,6 +263,9 @@ func TestSmartStatusOutputWidthChange(t *testing.T) { runner.startAction(action) smart.termWidth = 30 // Fake a SIGWINCH smartStat.sigwinch <- syscall.SIGWINCH <-smartStat.sigwinchHandled runner.finishAction(result) stat.Flush() Loading