1
1
package cli
2
2
3
3
import (
4
- "bufio"
5
4
"context"
6
5
"errors"
7
6
"flag"
@@ -14,14 +13,11 @@ import (
14
13
"os"
15
14
"os/signal"
16
15
"path/filepath"
17
- "regexp"
18
16
"runtime"
19
17
"strings"
20
18
"syscall"
21
19
"time"
22
- "unicode/utf8"
23
20
24
- "golang.org/x/crypto/ssh/terminal"
25
21
"golang.org/x/exp/slices"
26
22
"golang.org/x/xerrors"
27
23
@@ -822,89 +818,61 @@ func isConnectionError(err error) bool {
822
818
}
823
819
824
820
type prettyErrorFormatter struct {
825
- level int
826
- w io.Writer
827
- }
828
-
829
- func (prettyErrorFormatter ) prefixLines (spaces int , s string ) string {
830
- twidth , _ , err := terminal .GetSize (0 )
831
- if err != nil {
832
- twidth = 80
833
- }
834
-
835
- s = lipgloss .NewStyle ().Width (twidth - spaces ).Render (s )
836
-
837
- var b strings.Builder
838
- scanner := bufio .NewScanner (strings .NewReader (s ))
839
- for i := 0 ; scanner .Scan (); i ++ {
840
- // The first line is already padded.
841
- if i == 0 {
842
- _ , _ = fmt .Fprintf (& b , "%s\n " , scanner .Text ())
843
- continue
844
- }
845
- _ , _ = fmt .Fprintf (& b , "%s%s\n " , strings .Repeat (" " , spaces ), scanner .Text ())
846
- }
847
- return strings .TrimSuffix (strings .TrimSuffix (b .String (), "\n " ), " " )
821
+ w io.Writer
848
822
}
849
823
850
824
func (p * prettyErrorFormatter ) format (err error ) {
851
- underErr := errors .Unwrap (err )
852
-
853
- arrowStyle := lipgloss .NewStyle ().Foreground (lipgloss .Color ("#515151" ))
825
+ errTail := errors .Unwrap (err )
854
826
855
827
//nolint:errorlint
856
- if _ , ok := err .(* clibase.RunCommandError ); ok && p . level == 0 && underErr != nil {
857
- // We can do a better job now .
858
- p .format (underErr )
828
+ if _ , ok := err .(* clibase.RunCommandError ); ok && errTail != nil {
829
+ // Avoid extra nesting .
830
+ p .format (errTail )
859
831
return
860
832
}
861
833
862
- var (
863
- padding string
864
- arrowWidth int
865
- )
866
- if p .level > 0 {
867
- const arrow = "┗━ "
868
- arrowWidth = utf8 .RuneCount ([]byte (arrow ))
869
- padding = strings .Repeat (" " , arrowWidth * p .level )
870
- _ , _ = fmt .Fprintf (p .w , "%v%v" , padding , arrowStyle .Render (arrow ))
871
- }
872
-
873
- if underErr != nil {
874
- header := strings .TrimSuffix (err .Error (), ": " + underErr .Error ())
875
- _ , _ = fmt .Fprintf (p .w , "%s\n " , p .prefixLines (len (padding )+ arrowWidth , header ))
876
- p .level ++
877
- p .format (underErr )
878
- return
834
+ var headErr string
835
+ if errTail != nil {
836
+ headErr = strings .TrimSuffix (err .Error (), ": " + errTail .Error ())
837
+ } else {
838
+ headErr = err .Error ()
879
839
}
880
840
881
- {
882
- style := lipgloss .NewStyle ().Foreground (lipgloss .Color ("#D16644" )).Background (lipgloss .Color ("#000000" )).Bold (false )
883
- // This is the last error in a tree.
884
- p .wrappedPrintf (
885
- "%s\n " ,
886
- p .prefixLines (
887
- len (padding )+ arrowWidth ,
888
- fmt .Sprintf (
889
- "%s%s%s" ,
890
- lipgloss .NewStyle ().Inherit (style ).Underline (true ).Render ("ERROR" ),
891
- lipgloss .NewStyle ().Inherit (style ).Foreground (arrowStyle .GetForeground ()).Render (" ► " ),
892
- style .Render (err .Error ()),
893
- ),
894
- ),
895
- )
841
+ var msg string
842
+ var sdkError * codersdk.Error
843
+ if errors .As (err , & sdkError ) {
844
+ // We don't want to repeat the same error message twice, so we
845
+ // only show the SDK error on the top of the stack.
846
+ msg = sdkError .Message
847
+ if sdkError .Helper != "" {
848
+ msg = msg + "\n " + sdkError .Helper
849
+ }
850
+ // The SDK error is usually good enough, and we don't want to overwhelm
851
+ // the user with output.
852
+ errTail = nil
853
+ } else {
854
+ msg = headErr
896
855
}
897
- }
898
856
899
- func (p * prettyErrorFormatter ) wrappedPrintf (format string , a ... interface {}) {
900
- s := lipgloss .NewStyle ().Width (ttyWidth ()).Render (
901
- fmt .Sprintf (format , a ... ),
857
+ headStyle := lipgloss .NewStyle ().Foreground (lipgloss .Color ("#D16644" ))
858
+ p .printf (
859
+ headStyle ,
860
+ "%s" ,
861
+ msg ,
902
862
)
903
863
904
- // Not sure why, but lipgloss is adding extra spaces we need to remove.
905
- excessSpaceRe := regexp .MustCompile (`[[:blank:]]*\n[[:blank:]]*$` )
906
- s = excessSpaceRe .ReplaceAllString (s , "\n " )
864
+ tailStyle := headStyle .Copy ().Foreground (lipgloss .Color ("#969696" ))
865
+
866
+ if errTail != nil {
867
+ p .printf (headStyle , ": " )
868
+ // Grey out the less important, deep errors.
869
+ p .printf (tailStyle , "%s" , errTail .Error ())
870
+ }
871
+ p .printf (tailStyle , "\n " )
872
+ }
907
873
874
+ func (p * prettyErrorFormatter ) printf (style lipgloss.Style , format string , a ... interface {}) {
875
+ s := style .Render (fmt .Sprintf (format , a ... ))
908
876
_ , _ = p .w .Write (
909
877
[]byte (
910
878
s ,
0 commit comments