Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions cmd/tsgo/sys.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"github.com/microsoft/typescript-go/internal/tspath"
"github.com/microsoft/typescript-go/internal/vfs"
"github.com/microsoft/typescript-go/internal/vfs/osvfs"
"golang.org/x/term"
)

type osSys struct {
Expand Down Expand Up @@ -50,6 +51,19 @@ func (s *osSys) EndWrite() {
// todo: revisit if improving tsc/build/watch unittest baselines
}

func (s *osSys) WriteOutputIsTTY() bool {
return term.IsTerminal(int(os.Stdout.Fd()))
}

func (s *osSys) GetWidthOfTerminal() int {
width, _, _ := term.GetSize(int(os.Stdout.Fd()))
return width
}

func (s *osSys) GetEnvironmentVariable(name string) string {
return os.Getenv(name)
}

func newSystem() *osSys {
cwd, err := os.Getwd()
if err != nil {
Expand Down
3 changes: 2 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ require (
github.com/peter-evans/patience v0.3.0
github.com/zeebo/xxh3 v1.0.2
golang.org/x/sync v0.16.0
golang.org/x/sys v0.34.0
golang.org/x/sys v0.35.0
golang.org/x/term v0.34.0
golang.org/x/text v0.27.0
gotest.tools/v3 v3.5.2
)
Expand Down
6 changes: 4 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,10 @@ golang.org/x/mod v0.25.0 h1:n7a+ZbQKQA/Ysbyb0/6IbB1H/X41mKgbhfv7AfG/44w=
golang.org/x/mod v0.25.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw=
golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA=
golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI=
golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/term v0.34.0 h1:O/2T7POpk0ZZ7MAzMeWFSg6S5IpWd/RXDlM9hgM3DR4=
golang.org/x/term v0.34.0/go.mod h1:5jC53AEywhIVebHgPVeg0mj8OD3VO9OzclacVrqpaAw=
golang.org/x/text v0.27.0 h1:4fGWRpyh641NLlecmyl4LOe6yDdfaYNrGb2zdfo4JV4=
golang.org/x/text v0.27.0/go.mod h1:1D28KMCvyooCX9hBiosv5Tz/+YLxj0j7XhWjpSUF7CU=
golang.org/x/tools v0.34.0 h1:qIpSLOxeCYGg9TrcJokLBG4KFA6d795g0xkBkiESGlo=
Expand Down
4 changes: 4 additions & 0 deletions internal/core/tristate.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@ func (t Tristate) IsFalseOrUnknown() bool {
return t == TSFalse || t == TSUnknown
}

func (t Tristate) IsUnknown() bool {
return t == TSUnknown
}

func (t Tristate) DefaultIfUnknown(value Tristate) Tristate {
if t == TSUnknown {
return value
Expand Down
199 changes: 147 additions & 52 deletions internal/execute/outputs.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,82 @@ func createDiagnosticReporter(sys System, options *core.CompilerOptions) diagnos
}
}

func defaultIsPretty(sys System) bool {
return sys.WriteOutputIsTTY() && sys.GetEnvironmentVariable("NO_COLOR") == ""
}

func shouldBePretty(sys System, options *core.CompilerOptions) bool {
if options == nil || options.Pretty.IsTrueOrUnknown() {
// todo: return defaultIsPretty(sys);
return true
if options == nil || options.Pretty.IsUnknown() {
return defaultIsPretty(sys)
}
return options.Pretty.IsTrue()
}

type colors struct {
showColors bool

isWindows bool
isWindowsTerminal bool
isVSCode bool
supportsRicherColors bool
}

func createColors(sys System) *colors {
if !defaultIsPretty(sys) {
return &colors{showColors: false}
}

os := sys.GetEnvironmentVariable("OS")
isWindows := strings.Contains(strings.ToLower(os), "windows")
isWindowsTerminal := sys.GetEnvironmentVariable("WT_SESSION") != ""
isVSCode := sys.GetEnvironmentVariable("TERM_PROGRAM") == "vscode"
supportsRicherColors := sys.GetEnvironmentVariable("COLORTERM") == "truecolor" || sys.GetEnvironmentVariable("TERM") == "xterm-256color"

return &colors{
showColors: true,
isWindows: isWindows,
isWindowsTerminal: isWindowsTerminal,
isVSCode: isVSCode,
supportsRicherColors: supportsRicherColors,
}
}

func (c *colors) bold(str string) string {
if !c.showColors {
return str
}
return "\x1b[1m" + str + "\x1b[22m"
}

func (c *colors) blue(str string) string {
if !c.showColors {
return str
}

// Effectively Powershell and Command prompt users use cyan instead
// of blue because the default theme doesn't show blue with enough contrast.
if c.isWindows && !c.isWindowsTerminal && !c.isVSCode {
return c.brightWhite(str)
}
return "\x1b[94m" + str + "\x1b[39m"
}

func (c *colors) blueBackground(str string) string {
if !c.showColors {
return str
}
if c.supportsRicherColors {
return "\x1B[48;5;68m" + str + "\x1B[39;49m"
} else {
return "\x1b[44m" + str + "\x1B[39;49m"
}
return false
}

func (c *colors) brightWhite(str string) string {
if !c.showColors {
return str
}
return "\x1b[97m" + str + "\x1b[39m"
}

func createReportErrorSummary(sys System, options *core.CompilerOptions) func(diagnostics []*ast.Diagnostic) {
Expand Down Expand Up @@ -134,43 +204,42 @@ func getOptionsForHelp(commandLine *tsoptions.ParsedCommandLine) []*tsoptions.Co
}

func getHeader(sys System, message string) []string {
// !!! const colors = createColors(sys);
var header []string
// !!! terminalWidth := sys.GetWidthOfTerminal?.() ?? 0
const tsIconLength = 5

// const tsIconFirstLine = colors.blueBackground("".padStart(tsIconLength));
// const tsIconSecondLine = colors.blueBackground(colors.brightWhite("TS ".padStart(tsIconLength)));
// // If we have enough space, print TS icon.
// if (terminalWidth >= message.length + tsIconLength) {
// // right align of the icon is 120 at most.
// const rightAlign = terminalWidth > 120 ? 120 : terminalWidth;
// const leftAlign = rightAlign - tsIconLength;
// header.push(message.padEnd(leftAlign) + tsIconFirstLine + sys.newLine);
// header.push("".padStart(leftAlign) + tsIconSecondLine + sys.newLine);
// }
// else {
header = append(header, message+"\n", "\n")
// }
colors := createColors(sys)
header := make([]string, 0, 3)
terminalWidth := sys.GetWidthOfTerminal()
const tsIcon = " "
const tsIconTS = " TS "
const tsIconLength = len(tsIcon)

tsIconFirstLine := colors.blueBackground(tsIcon)
tsIconSecondLine := colors.blueBackground(colors.brightWhite(tsIconTS))
// If we have enough space, print TS icon.
if terminalWidth >= len(message)+tsIconLength {
// right align of the icon is 120 at most.
rightAlign := core.IfElse(terminalWidth > 120, 120, terminalWidth)
leftAlign := rightAlign - tsIconLength
header = append(header, fmt.Sprintf("%-*s", leftAlign, message), tsIconFirstLine, "\n")
header = append(header, strings.Repeat(" ", leftAlign), tsIconSecondLine, "\n")
} else {
header = append(header, message, "\n", "\n")
}
return header
}

func printEasyHelp(sys System, simpleOptions []*tsoptions.CommandLineOption) {
// !!! const colors = createColors(sys);
colors := createColors(sys)
var output []string
example := func(examples []string, desc *diagnostics.Message) {
for _, example := range examples {
// !!! colors
// output.push(" " + colors.blue(example) + sys.newLine);
output = append(output, " ", example, "\n")
output = append(output, " ", colors.blue(example), "\n")
}
output = append(output, " ", desc.Format(), "\n", "\n")
}

msg := diagnostics.X_tsc_Colon_The_TypeScript_Compiler.Format() + " - " + diagnostics.Version_0.Format(core.Version())
output = append(output, getHeader(sys, msg)...)

output = append(output /*colors.bold(*/, diagnostics.COMMON_COMMANDS.Format() /*)*/, "\n", "\n")
output = append(output, colors.bold(diagnostics.COMMON_COMMANDS.Format()), "\n", "\n")

example([]string{"tsc"}, diagnostics.Compiles_the_current_project_tsconfig_json_in_the_working_directory)
example([]string{"tsc app.ts util.ts"}, diagnostics.Ignoring_tsconfig_json_compiles_the_specified_files_with_default_compiler_options)
Expand All @@ -192,10 +261,9 @@ func printEasyHelp(sys System, simpleOptions []*tsoptions.CommandLineOption) {

output = append(output, generateSectionOptionsOutput(sys, diagnostics.COMMAND_LINE_FLAGS.Format(), cliCommands /*subCategory*/, false /*beforeOptionsDescription*/, nil /*afterOptionsDescription*/, nil)...)

// !!! locale formatMessage
after := diagnostics.You_can_learn_about_all_of_the_compiler_options_at_0.Format("https://aka.ms/tsc")
output = append(output, generateSectionOptionsOutput(sys, diagnostics.COMMON_COMPILER_OPTIONS.Format(), configOpts /*subCategory*/, false /*beforeOptionsDescription*/, nil,
// !!! locale formatMessage(Diagnostics.You_can_learn_about_all_of_the_compiler_options_at_0, "https://aka.ms/tsc")),
&after)...)
output = append(output, generateSectionOptionsOutput(sys, diagnostics.COMMON_COMPILER_OPTIONS.Format(), configOpts /*subCategory*/, false /*beforeOptionsDescription*/, nil, &after)...)

for _, chunk := range output {
fmt.Fprint(sys.Writer(), chunk)
Expand All @@ -211,8 +279,7 @@ func generateSectionOptionsOutput(
beforeOptionsDescription,
afterOptionsDescription *string,
) (output []string) {
// !!! color
output = append(output /*createColors(sys).bold(*/, sectionName /*)*/, "\n", "\n")
output = append(output, createColors(sys).bold(sectionName), "\n", "\n")

if beforeOptionsDescription != nil {
output = append(output, *beforeOptionsDescription, "\n", "\n")
Expand Down Expand Up @@ -274,10 +341,10 @@ func generateGroupOptionOutput(sys System, optionsList []*tsoptions.CommandLineO
func generateOptionOutput(
sys System,
option *tsoptions.CommandLineOption,
rightAlignOfLeftPart, leftAlignOfRightPart int,
rightAlignOfLeft, leftAlignOfRight int,
) []string {
var text []string
// !!! const colors = createColors(sys);
colors := createColors(sys)

// name and description
name := getDisplayNameTextOfOption(option)
Expand All @@ -298,27 +365,28 @@ func generateOptionOutput(
)
}

var terminalWidth int
// !!! const terminalWidth = sys.getWidthOfTerminal?.() ?? 0;
terminalWidth := sys.GetWidthOfTerminal()

// Note: child_process might return `terminalWidth` as undefined.
if terminalWidth >= 80 {
// !!! let description = "";
// !!! if (option.description) {
// !!! description = getDiagnosticText(option.description);
// !!! }
// !!! text.push(...getPrettyOutput(name, description, rightAlignOfLeft, leftAlignOfRight, terminalWidth, /*colorLeft*/ true), sys.newLine);
// !!! if (showAdditionalInfoOutput(valueCandidates, option)) {
// !!! if (valueCandidates) {
// !!! text.push(...getPrettyOutput(valueCandidates.valueType, valueCandidates.possibleValues, rightAlignOfLeft, leftAlignOfRight, terminalWidth, /*colorLeft*/ false), sys.newLine);
// !!! }
// !!! if (defaultValueDescription) {
// !!! text.push(...getPrettyOutput(getDiagnosticText(Diagnostics.default_Colon), defaultValueDescription, rightAlignOfLeft, leftAlignOfRight, terminalWidth, /*colorLeft*/ false), sys.newLine);
// !!! }
// !!! }
// !!! text.push(sys.newLine);
description := ""
if option.Description != nil {
description = option.Description.Format()
}
text = append(text, getPrettyOutput(colors, name, description, rightAlignOfLeft, leftAlignOfRight, terminalWidth, true /*colorLeft*/)...)
text = append(text, "\n")
if showAdditionalInfoOutput(valueCandidates, option) {
if valueCandidates != nil {
text = append(text, getPrettyOutput(colors, valueCandidates.valueType, valueCandidates.possibleValues, rightAlignOfLeft, leftAlignOfRight, terminalWidth, false /*colorLeft*/)...)
text = append(text, "\n")
}
if defaultValueDescription != "" {
text = append(text, getPrettyOutput(colors, diagnostics.X_default_Colon.Format(), defaultValueDescription, rightAlignOfLeft, leftAlignOfRight, terminalWidth, false /*colorLeft*/)...)
text = append(text, "\n")
}
}
text = append(text, "\n")
} else {
text = append(text /* !!! colors.blue(name) */, name, "\n")
text = append(text, colors.blue(name), "\n")
if option.Description != nil {
text = append(text, option.Description.Format())
}
Expand Down Expand Up @@ -444,6 +512,33 @@ func getPossibleValues(option *tsoptions.CommandLineOption) string {
}
}

func getPrettyOutput(colors *colors, left string, right string, rightAlignOfLeft int, leftAlignOfRight int, terminalWidth int, colorLeft bool) []string {
// !!! How does terminalWidth interact with UTF-8 encoding? Strada just assumed UTF-16.
res := make([]string, 0, 4)
isFirstLine := true
remainRight := right
rightCharacterNumber := terminalWidth - leftAlignOfRight
for len(remainRight) > 0 {
curLeft := ""
if isFirstLine {
curLeft = fmt.Sprintf("%*s", rightAlignOfLeft, left)
curLeft = fmt.Sprintf("%-*s", leftAlignOfRight, curLeft)
if colorLeft {
curLeft = colors.blue(curLeft)
}
} else {
curLeft = strings.Repeat(" ", leftAlignOfRight)
}

idx := min(rightCharacterNumber, len(remainRight))
curRight := remainRight[:idx]
remainRight = remainRight[idx:]
res = append(res, curLeft, curRight, "\n")
isFirstLine = false
}
return res
}

func getDisplayNameTextOfOption(option *tsoptions.CommandLineOption) string {
return "--" + option.Name + core.IfElse(option.ShortName != "", ", -"+option.ShortName, "")
}
Expand Down
3 changes: 3 additions & 0 deletions internal/execute/system.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ type System interface {
FS() vfs.FS
DefaultLibraryPath() string
GetCurrentDirectory() string
WriteOutputIsTTY() bool
GetWidthOfTerminal() int
GetEnvironmentVariable(name string) string

Now() time.Time
SinceStart() time.Duration
Expand Down
20 changes: 19 additions & 1 deletion internal/execute/testsys_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"io/fs"
"maps"
"slices"
"strconv"
"strings"
"time"

Expand Down Expand Up @@ -50,7 +51,7 @@ interface Symbol {
declare const console: { log(msg: any): void; };
`)

func newTestSys(fileOrFolderList FileMap, cwd string) *testSys {
func newTestSys(fileOrFolderList FileMap, cwd string, env map[string]string) *testSys {
if cwd == "" {
cwd = "/home/src/workspaces/project"
}
Expand All @@ -66,6 +67,7 @@ func newTestSys(fileOrFolderList FileMap, cwd string) *testSys {
output: []string{},
currentWrite: &strings.Builder{},
start: time.Now(),
env: env,
}

// Ensure the default library file is present
Expand Down Expand Up @@ -99,6 +101,7 @@ type testSys struct {
defaultLibraryPath string
cwd string
files []string
env map[string]string

start time.Time
}
Expand Down Expand Up @@ -152,6 +155,21 @@ func (s *testSys) Writer() io.Writer {
return s.currentWrite
}

func (s *testSys) WriteOutputIsTTY() bool {
return true
}

func (s *testSys) GetWidthOfTerminal() int {
if widthStr := s.GetEnvironmentVariable("TS_TEST_TERMINAL_WIDTH"); widthStr != "" {
return core.Must(strconv.Atoi(widthStr))
}
return 0
}

func (s *testSys) GetEnvironmentVariable(name string) string {
return s.env[name]
}

func sanitizeSysOutput(output string, prefixLine string, replaceString string) string {
if index := strings.Index(output, prefixLine); index != -1 {
indexOfNewLine := strings.Index(output[index:], "\n")
Expand Down
Loading
Loading