diff --git a/cli/cliui/agent.go b/cli/cliui/agent.go index 8973606ec71da..f1f14dfef1f51 100644 --- a/cli/cliui/agent.go +++ b/cli/cliui/agent.go @@ -179,7 +179,7 @@ type message struct { func waitingMessage(agent codersdk.WorkspaceAgent, opts AgentOptions) (m *message) { m = &message{ - Spin: fmt.Sprintf("Waiting for connection from %s...", Styles.Field.Render(agent.Name)), + Spin: fmt.Sprintf("Waiting for connection from %s...", DefaultStyles.Field.Render(agent.Name)), Prompt: "Don't panic, your workspace is booting up!", } defer func() { @@ -192,7 +192,7 @@ func waitingMessage(agent codersdk.WorkspaceAgent, opts AgentOptions) (m *messag // We don't want to wrap the troubleshooting URL, so we'll handle word // wrapping ourselves (vs using lipgloss). - w := wordwrap.NewWriter(Styles.Paragraph.GetWidth() - Styles.Paragraph.GetMarginLeft()*2) + w := wordwrap.NewWriter(DefaultStyles.Paragraph.GetWidth() - DefaultStyles.Paragraph.GetMarginLeft()*2) w.Breakpoints = []rune{' ', '\n'} _, _ = fmt.Fprint(w, m.Prompt) @@ -208,7 +208,7 @@ func waitingMessage(agent codersdk.WorkspaceAgent, opts AgentOptions) (m *messag // We want to prefix the prompt with a caret, but we want text on the // following lines to align with the text on the first line (i.e. added // spacing). - ind := " " + Styles.Prompt.String() + ind := " " + DefaultStyles.Prompt.String() iw := indent.NewWriter(1, func(w io.Writer) { _, _ = w.Write([]byte(ind)) ind = " " // Set indentation to space after initial prompt. @@ -223,7 +223,7 @@ func waitingMessage(agent codersdk.WorkspaceAgent, opts AgentOptions) (m *messag case codersdk.WorkspaceAgentDisconnected: m.Prompt = "The workspace agent lost connection!" case codersdk.WorkspaceAgentConnected: - m.Spin = fmt.Sprintf("Waiting for %s to become ready...", Styles.Field.Render(agent.Name)) + m.Spin = fmt.Sprintf("Waiting for %s to become ready...", DefaultStyles.Field.Render(agent.Name)) m.Prompt = "Don't panic, your workspace agent has connected and the workspace is getting ready!" if opts.NoWait { m.Prompt = "Your workspace is still getting ready, it may be in an incomplete state." diff --git a/cli/cliui/cliui.go b/cli/cliui/cliui.go index a94f736e8ddf2..b59ccd61298cc 100644 --- a/cli/cliui/cliui.go +++ b/cli/cliui/cliui.go @@ -1,27 +1,20 @@ package cliui import ( + "os" + "github.com/charmbracelet/charm/ui/common" "github.com/charmbracelet/lipgloss" + "github.com/muesli/termenv" "golang.org/x/xerrors" ) -var ( - Canceled = xerrors.New("canceled") - - defaultStyles = common.DefaultStyles() -) +var Canceled = xerrors.New("canceled") -// ValidateNotEmpty is a helper function to disallow empty inputs! -func ValidateNotEmpty(s string) error { - if s == "" { - return xerrors.New("Must be provided!") - } - return nil -} +// DefaultStyles compose visual elements of the UI. +var DefaultStyles Styles -// Styles compose visual elements of the UI! -var Styles = struct { +type Styles struct { Bold, Checkmark, Code, @@ -38,23 +31,45 @@ var Styles = struct { Logo, Warn, Wrap lipgloss.Style -}{ - Bold: lipgloss.NewStyle().Bold(true), - Checkmark: defaultStyles.Checkmark, - Code: defaultStyles.Code, - Crossmark: defaultStyles.Error.Copy().SetString("✘"), - DateTimeStamp: defaultStyles.LabelDim, - Error: defaultStyles.Error, - Field: defaultStyles.Code.Copy().Foreground(lipgloss.AdaptiveColor{Light: "#000000", Dark: "#FFFFFF"}), - Keyword: defaultStyles.Keyword, - Paragraph: defaultStyles.Paragraph, - Placeholder: lipgloss.NewStyle().Foreground(lipgloss.AdaptiveColor{Light: "#585858", Dark: "#4d46b3"}), - Prompt: defaultStyles.Prompt.Copy().Foreground(lipgloss.AdaptiveColor{Light: "#9B9B9B", Dark: "#5C5C5C"}), - FocusedPrompt: defaultStyles.FocusedPrompt.Copy().Foreground(lipgloss.Color("#651fff")), - Fuchsia: defaultStyles.SelectedMenuItem.Copy(), - Logo: defaultStyles.Logo.Copy().SetString("Coder"), - Warn: lipgloss.NewStyle().Foreground( - lipgloss.AdaptiveColor{Light: "#04B575", Dark: "#ECFD65"}, - ), - Wrap: lipgloss.NewStyle().Width(80), +} + +func init() { + lipgloss.SetDefaultRenderer( + lipgloss.NewRenderer(os.Stdout, termenv.WithColorCache(true)), + ) + + // All Styles are set after we change the DefaultRenderer so that the ColorCache + // is in effect, mitigating the severe performance issue seen here: + // https://github.com/coder/coder/issues/7884. + + charmStyles := common.DefaultStyles() + + DefaultStyles = Styles{ + Bold: lipgloss.NewStyle().Bold(true), + Checkmark: charmStyles.Checkmark, + Code: charmStyles.Code, + Crossmark: charmStyles.Error.Copy().SetString("✘"), + DateTimeStamp: charmStyles.LabelDim, + Error: charmStyles.Error, + Field: charmStyles.Code.Copy().Foreground(lipgloss.AdaptiveColor{Light: "#000000", Dark: "#FFFFFF"}), + Keyword: charmStyles.Keyword, + Paragraph: charmStyles.Paragraph, + Placeholder: lipgloss.NewStyle().Foreground(lipgloss.AdaptiveColor{Light: "#585858", Dark: "#4d46b3"}), + Prompt: charmStyles.Prompt.Copy().Foreground(lipgloss.AdaptiveColor{Light: "#9B9B9B", Dark: "#5C5C5C"}), + FocusedPrompt: charmStyles.FocusedPrompt.Copy().Foreground(lipgloss.Color("#651fff")), + Fuchsia: charmStyles.SelectedMenuItem.Copy(), + Logo: charmStyles.Logo.Copy().SetString("Coder"), + Warn: lipgloss.NewStyle().Foreground( + lipgloss.AdaptiveColor{Light: "#04B575", Dark: "#ECFD65"}, + ), + Wrap: lipgloss.NewStyle().Width(80), + } +} + +// ValidateNotEmpty is a helper function to disallow empty inputs! +func ValidateNotEmpty(s string) error { + if s == "" { + return xerrors.New("Must be provided!") + } + return nil } diff --git a/cli/cliui/log.go b/cli/cliui/log.go index 290dd713d645c..fcc1d9b317c17 100644 --- a/cli/cliui/log.go +++ b/cli/cliui/log.go @@ -35,7 +35,7 @@ func (m cliMessage) String() string { // Warn writes a log to the writer provided. func Warn(wtr io.Writer, header string, lines ...string) { _, _ = fmt.Fprint(wtr, cliMessage{ - Style: Styles.Warn.Copy(), + Style: DefaultStyles.Warn.Copy(), Prefix: "WARN: ", Header: header, Lines: lines, @@ -63,7 +63,7 @@ func Infof(wtr io.Writer, fmtStr string, args ...interface{}) { // Error writes a log to the writer provided. func Error(wtr io.Writer, header string, lines ...string) { _, _ = fmt.Fprint(wtr, cliMessage{ - Style: Styles.Error.Copy(), + Style: DefaultStyles.Error.Copy(), Prefix: "ERROR: ", Header: header, Lines: lines, diff --git a/cli/cliui/parameter.go b/cli/cliui/parameter.go index 8e8d071160930..1d43b7fc4dde8 100644 --- a/cli/cliui/parameter.go +++ b/cli/cliui/parameter.go @@ -15,7 +15,7 @@ func RichParameter(inv *clibase.Invocation, templateVersionParameter codersdk.Te label = templateVersionParameter.DisplayName } - _, _ = fmt.Fprintln(inv.Stdout, Styles.Bold.Render(label)) + _, _ = fmt.Fprintln(inv.Stdout, DefaultStyles.Bold.Render(label)) if templateVersionParameter.DescriptionPlaintext != "" { _, _ = fmt.Fprintln(inv.Stdout, " "+strings.TrimSpace(strings.Join(strings.Split(templateVersionParameter.DescriptionPlaintext, "\n"), "\n "))+"\n") } @@ -40,7 +40,7 @@ func RichParameter(inv *clibase.Invocation, templateVersionParameter codersdk.Te } _, _ = fmt.Fprintln(inv.Stdout) - _, _ = fmt.Fprintln(inv.Stdout, " "+Styles.Prompt.String()+Styles.Field.Render(strings.Join(values, ", "))) + _, _ = fmt.Fprintln(inv.Stdout, " "+DefaultStyles.Prompt.String()+DefaultStyles.Field.Render(strings.Join(values, ", "))) value = string(v) } } else if len(templateVersionParameter.Options) > 0 { @@ -54,7 +54,7 @@ func RichParameter(inv *clibase.Invocation, templateVersionParameter codersdk.Te }) if err == nil { _, _ = fmt.Fprintln(inv.Stdout) - _, _ = fmt.Fprintln(inv.Stdout, " "+Styles.Prompt.String()+Styles.Field.Render(richParameterOption.Name)) + _, _ = fmt.Fprintln(inv.Stdout, " "+DefaultStyles.Prompt.String()+DefaultStyles.Field.Render(richParameterOption.Name)) value = richParameterOption.Value } } else { @@ -65,7 +65,7 @@ func RichParameter(inv *clibase.Invocation, templateVersionParameter codersdk.Te text += ":" value, err = Prompt(inv, PromptOptions{ - Text: Styles.Bold.Render(text), + Text: DefaultStyles.Bold.Render(text), Validate: func(value string) error { return validateRichPrompt(value, templateVersionParameter) }, diff --git a/cli/cliui/prompt.go b/cli/cliui/prompt.go index 7ce927c0b6b7d..f927b60749769 100644 --- a/cli/cliui/prompt.go +++ b/cli/cliui/prompt.go @@ -55,21 +55,21 @@ func Prompt(inv *clibase.Invocation, opts PromptOptions) (string, error) { } } - _, _ = fmt.Fprint(inv.Stdout, Styles.FocusedPrompt.String()+opts.Text+" ") + _, _ = fmt.Fprint(inv.Stdout, DefaultStyles.FocusedPrompt.String()+opts.Text+" ") if opts.IsConfirm { if len(opts.Default) == 0 { opts.Default = ConfirmYes } - renderedYes := Styles.Placeholder.Render(ConfirmYes) - renderedNo := Styles.Placeholder.Render(ConfirmNo) + renderedYes := DefaultStyles.Placeholder.Render(ConfirmYes) + renderedNo := DefaultStyles.Placeholder.Render(ConfirmNo) if opts.Default == ConfirmYes { - renderedYes = Styles.Bold.Render(ConfirmYes) + renderedYes = DefaultStyles.Bold.Render(ConfirmYes) } else { - renderedNo = Styles.Bold.Render(ConfirmNo) + renderedNo = DefaultStyles.Bold.Render(ConfirmNo) } - _, _ = fmt.Fprint(inv.Stdout, Styles.Placeholder.Render("("+renderedYes+Styles.Placeholder.Render("/"+renderedNo+Styles.Placeholder.Render(") ")))) + _, _ = fmt.Fprint(inv.Stdout, DefaultStyles.Placeholder.Render("("+renderedYes+DefaultStyles.Placeholder.Render("/"+renderedNo+DefaultStyles.Placeholder.Render(") ")))) } else if opts.Default != "" { - _, _ = fmt.Fprint(inv.Stdout, Styles.Placeholder.Render("("+opts.Default+") ")) + _, _ = fmt.Fprint(inv.Stdout, DefaultStyles.Placeholder.Render("("+opts.Default+") ")) } interrupt := make(chan os.Signal, 1) @@ -126,7 +126,7 @@ func Prompt(inv *clibase.Invocation, opts PromptOptions) (string, error) { if opts.Validate != nil { err := opts.Validate(line) if err != nil { - _, _ = fmt.Fprintln(inv.Stdout, defaultStyles.Error.Render(err.Error())) + _, _ = fmt.Fprintln(inv.Stdout, DefaultStyles.Error.Render(err.Error())) return Prompt(inv, opts) } } diff --git a/cli/cliui/provisionerjob.go b/cli/cliui/provisionerjob.go index f5289c2bf0961..f8282465a3d56 100644 --- a/cli/cliui/provisionerjob.go +++ b/cli/cliui/provisionerjob.go @@ -71,7 +71,7 @@ func ProvisionerJob(ctx context.Context, writer io.Writer, opts ProvisionerJobOp ) printStage := func() { - _, _ = fmt.Fprintf(writer, Styles.Prompt.Render("⧗")+"%s\n", Styles.Field.Render(currentStage)) + _, _ = fmt.Fprintf(writer, DefaultStyles.Prompt.Render("⧗")+"%s\n", DefaultStyles.Field.Render(currentStage)) } updateStage := func(stage string, startedAt time.Time) { @@ -80,11 +80,11 @@ func ProvisionerJob(ctx context.Context, writer io.Writer, opts ProvisionerJobOp if !didLogBetweenStage { prefix = "\033[1A\r" } - mark := Styles.Checkmark + mark := DefaultStyles.Checkmark if job.CompletedAt != nil && job.Status != codersdk.ProvisionerJobSucceeded { - mark = Styles.Crossmark + mark = DefaultStyles.Crossmark } - _, _ = fmt.Fprintf(writer, prefix+mark.String()+Styles.Placeholder.Render(" %s [%dms]")+"\n", currentStage, startedAt.Sub(currentStageStartedAt).Milliseconds()) + _, _ = fmt.Fprintf(writer, prefix+mark.String()+DefaultStyles.Placeholder.Render(" %s [%dms]")+"\n", currentStage, startedAt.Sub(currentStageStartedAt).Milliseconds()) } if stage == "" { return @@ -129,7 +129,7 @@ func ProvisionerJob(ctx context.Context, writer io.Writer, opts ProvisionerJobOp return } } - _, _ = fmt.Fprintf(writer, "\033[2K\r\n"+Styles.FocusedPrompt.String()+Styles.Bold.Render("Gracefully canceling...")+"\n\n") + _, _ = fmt.Fprintf(writer, "\033[2K\r\n"+DefaultStyles.FocusedPrompt.String()+DefaultStyles.Bold.Render("Gracefully canceling...")+"\n\n") err := opts.Cancel() if err != nil { errChan <- xerrors.Errorf("cancel: %w", err) @@ -207,11 +207,11 @@ func ProvisionerJob(ctx context.Context, writer io.Writer, opts ProvisionerJobOp if !opts.Verbose { continue } - output = Styles.Placeholder.Render(log.Output) + output = DefaultStyles.Placeholder.Render(log.Output) case codersdk.LogLevelError: - output = defaultStyles.Error.Render(log.Output) + output = DefaultStyles.Error.Render(log.Output) case codersdk.LogLevelWarn: - output = Styles.Warn.Render(log.Output) + output = DefaultStyles.Warn.Render(log.Output) case codersdk.LogLevelInfo: output = log.Output } @@ -222,7 +222,7 @@ func ProvisionerJob(ctx context.Context, writer io.Writer, opts ProvisionerJobOp jobMutex.Unlock() continue } - _, _ = fmt.Fprintf(logOutput, "%s %s\n", Styles.Placeholder.Render(" "), output) + _, _ = fmt.Fprintf(logOutput, "%s %s\n", DefaultStyles.Placeholder.Render(" "), output) if !opts.Silent { didLogBetweenStage = true } diff --git a/cli/cliui/resources.go b/cli/cliui/resources.go index 1f2d8c0992ba3..def5d6942bcb3 100644 --- a/cli/cliui/resources.go +++ b/cli/cliui/resources.go @@ -78,7 +78,7 @@ func WorkspaceResources(writer io.Writer, resources []codersdk.WorkspaceResource // Display a line for the resource. tableWriter.AppendRow(table.Row{ - Styles.Bold.Render(resourceAddress), + DefaultStyles.Bold.Render(resourceAddress), "", "", }) @@ -106,7 +106,7 @@ func WorkspaceResources(writer io.Writer, resources []codersdk.WorkspaceResource if totalAgents > 1 { sshCommand += "." + agent.Name } - sshCommand = Styles.Code.Render(sshCommand) + sshCommand = DefaultStyles.Code.Render(sshCommand) row = append(row, sshCommand) } tableWriter.AppendRow(row) @@ -121,23 +121,23 @@ func renderAgentStatus(agent codersdk.WorkspaceAgent) string { switch agent.Status { case codersdk.WorkspaceAgentConnecting: since := database.Now().Sub(agent.CreatedAt) - return Styles.Warn.Render("⦾ connecting") + " " + - Styles.Placeholder.Render("["+strconv.Itoa(int(since.Seconds()))+"s]") + return DefaultStyles.Warn.Render("⦾ connecting") + " " + + DefaultStyles.Placeholder.Render("["+strconv.Itoa(int(since.Seconds()))+"s]") case codersdk.WorkspaceAgentDisconnected: since := database.Now().Sub(*agent.DisconnectedAt) - return Styles.Error.Render("⦾ disconnected") + " " + - Styles.Placeholder.Render("["+strconv.Itoa(int(since.Seconds()))+"s]") + return DefaultStyles.Error.Render("⦾ disconnected") + " " + + DefaultStyles.Placeholder.Render("["+strconv.Itoa(int(since.Seconds()))+"s]") case codersdk.WorkspaceAgentTimeout: since := database.Now().Sub(agent.CreatedAt) return fmt.Sprintf( "%s %s", - Styles.Warn.Render("⦾ timeout"), - Styles.Placeholder.Render("["+strconv.Itoa(int(since.Seconds()))+"s]"), + DefaultStyles.Warn.Render("⦾ timeout"), + DefaultStyles.Placeholder.Render("["+strconv.Itoa(int(since.Seconds()))+"s]"), ) case codersdk.WorkspaceAgentConnected: - return Styles.Keyword.Render("⦿ connected") + return DefaultStyles.Keyword.Render("⦿ connected") default: - return Styles.Warn.Render("○ unknown") + return DefaultStyles.Warn.Render("○ unknown") } } @@ -146,11 +146,11 @@ func renderAgentVersion(agentVersion, serverVersion string) string { agentVersion = "(unknown)" } if !semver.IsValid(serverVersion) || !semver.IsValid(agentVersion) { - return Styles.Placeholder.Render(agentVersion) + return DefaultStyles.Placeholder.Render(agentVersion) } outdated := semver.Compare(agentVersion, serverVersion) < 0 if outdated { - return Styles.Warn.Render(agentVersion + " (outdated)") + return DefaultStyles.Warn.Render(agentVersion + " (outdated)") } - return Styles.Keyword.Render(agentVersion) + return DefaultStyles.Keyword.Render(agentVersion) } diff --git a/cli/create.go b/cli/create.go index 1e6e5cd550983..b7ffbec5819cb 100644 --- a/cli/create.go +++ b/cli/create.go @@ -63,7 +63,7 @@ func (r *RootCmd) create() *clibase.Cmd { var template codersdk.Template if templateName == "" { - _, _ = fmt.Fprintln(inv.Stdout, cliui.Styles.Wrap.Render("Select a template below to preview the provisioned infrastructure:")) + _, _ = fmt.Fprintln(inv.Stdout, cliui.DefaultStyles.Wrap.Render("Select a template below to preview the provisioned infrastructure:")) templates, err := client.TemplatesByOrganization(inv.Context(), organization.ID) if err != nil { @@ -81,7 +81,7 @@ func (r *RootCmd) create() *clibase.Cmd { templateName := template.Name if template.ActiveUserCount > 0 { - templateName += cliui.Styles.Placeholder.Render( + templateName += cliui.DefaultStyles.Placeholder.Render( fmt.Sprintf( " (used by %s)", formatActiveDevelopers(template.ActiveUserCount), @@ -159,7 +159,7 @@ func (r *RootCmd) create() *clibase.Cmd { return xerrors.Errorf("watch build: %w", err) } - _, _ = fmt.Fprintf(inv.Stdout, "\nThe %s workspace has been created at %s!\n", cliui.Styles.Keyword.Render(workspace.Name), cliui.Styles.DateTimeStamp.Render(time.Now().Format(time.Stamp))) + _, _ = fmt.Fprintf(inv.Stdout, "\nThe %s workspace has been created at %s!\n", cliui.DefaultStyles.Keyword.Render(workspace.Name), cliui.DefaultStyles.DateTimeStamp.Render(time.Now().Format(time.Stamp))) return nil }, } @@ -230,7 +230,7 @@ func prepWorkspaceBuild(inv *clibase.Invocation, client *codersdk.Client, args p useParamFile := false if args.RichParameterFile != "" { useParamFile = true - _, _ = fmt.Fprintln(inv.Stdout, cliui.Styles.Paragraph.Render("Attempting to read the variables from the rich parameter file.")+"\r\n") + _, _ = fmt.Fprintln(inv.Stdout, cliui.DefaultStyles.Paragraph.Render("Attempting to read the variables from the rich parameter file.")+"\r\n") parameterMapFromFile, err = createParameterMapFromFile(args.RichParameterFile) if err != nil { return nil, err @@ -241,7 +241,7 @@ func prepWorkspaceBuild(inv *clibase.Invocation, client *codersdk.Client, args p PromptRichParamLoop: for _, templateVersionParameter := range templateVersionParameters { if !disclaimerPrinted { - _, _ = fmt.Fprintln(inv.Stdout, cliui.Styles.Paragraph.Render("This template has customizable parameters. Values can be changed after create, but may have unintended side effects (like data loss).")+"\r\n") + _, _ = fmt.Fprintln(inv.Stdout, cliui.DefaultStyles.Paragraph.Render("This template has customizable parameters. Values can be changed after create, but may have unintended side effects (like data loss).")+"\r\n") disclaimerPrinted = true } @@ -265,7 +265,7 @@ PromptRichParamLoop: } if exists { - _, _ = fmt.Fprintln(inv.Stdout, cliui.Styles.Warn.Render(fmt.Sprintf(`Parameter %q is not mutable, so can't be customized after workspace creation.`, templateVersionParameter.Name))) + _, _ = fmt.Fprintln(inv.Stdout, cliui.DefaultStyles.Warn.Render(fmt.Sprintf(`Parameter %q is not mutable, so can't be customized after workspace creation.`, templateVersionParameter.Name))) continue } } diff --git a/cli/delete.go b/cli/delete.go index f87b02d7df880..867abe0326a30 100644 --- a/cli/delete.go +++ b/cli/delete.go @@ -51,7 +51,7 @@ func (r *RootCmd) deleteWorkspace() *clibase.Cmd { return err } - _, _ = fmt.Fprintf(inv.Stdout, "\nThe %s workspace has been deleted at %s!\n", cliui.Styles.Keyword.Render(workspace.Name), cliui.Styles.DateTimeStamp.Render(time.Now().Format(time.Stamp))) + _, _ = fmt.Fprintf(inv.Stdout, "\nThe %s workspace has been deleted at %s!\n", cliui.DefaultStyles.Keyword.Render(workspace.Name), cliui.DefaultStyles.DateTimeStamp.Render(time.Now().Format(time.Stamp))) return nil }, } diff --git a/cli/dotfiles.go b/cli/dotfiles.go index 6185ebae97948..3d9b8feb71f47 100644 --- a/cli/dotfiles.go +++ b/cli/dotfiles.go @@ -137,7 +137,7 @@ func (r *RootCmd) dotfiles() *clibase.Cmd { return err } // if the repo exists we soft fail the update operation and try to continue - _, _ = fmt.Fprintln(inv.Stdout, cliui.Styles.Error.Render("Failed to update repo, continuing...")) + _, _ = fmt.Fprintln(inv.Stdout, cliui.DefaultStyles.Error.Render("Failed to update repo, continuing...")) } // save git repo url so we can detect changes next time diff --git a/cli/gitssh.go b/cli/gitssh.go index 70af9ebd3ef08..6c4046c03cafe 100644 --- a/cli/gitssh.go +++ b/cli/gitssh.go @@ -90,12 +90,12 @@ func (r *RootCmd) gitssh() *clibase.Cmd { exitErr := &exec.ExitError{} if xerrors.As(err, &exitErr) && exitErr.ExitCode() == 255 { _, _ = fmt.Fprintln(inv.Stderr, - "\n"+cliui.Styles.Wrap.Render("Coder authenticates with "+cliui.Styles.Field.Render("git")+ + "\n"+cliui.DefaultStyles.Wrap.Render("Coder authenticates with "+cliui.DefaultStyles.Field.Render("git")+ " using the public key below. All clones with SSH are authenticated automatically 🪄.")+"\n") - _, _ = fmt.Fprintln(inv.Stderr, cliui.Styles.Code.Render(strings.TrimSpace(key.PublicKey))+"\n") + _, _ = fmt.Fprintln(inv.Stderr, cliui.DefaultStyles.Code.Render(strings.TrimSpace(key.PublicKey))+"\n") _, _ = fmt.Fprintln(inv.Stderr, "Add to GitHub and GitLab:") - _, _ = fmt.Fprintln(inv.Stderr, cliui.Styles.Prompt.String()+"https://github.com/settings/ssh/new") - _, _ = fmt.Fprintln(inv.Stderr, cliui.Styles.Prompt.String()+"https://gitlab.com/-/profile/keys") + _, _ = fmt.Fprintln(inv.Stderr, cliui.DefaultStyles.Prompt.String()+"https://github.com/settings/ssh/new") + _, _ = fmt.Fprintln(inv.Stderr, cliui.DefaultStyles.Prompt.String()+"https://gitlab.com/-/profile/keys") _, _ = fmt.Fprintln(inv.Stderr) return err } diff --git a/cli/help.go b/cli/help.go index 4fa18455c2c5b..6fb5066a152d1 100644 --- a/cli/help.go +++ b/cli/help.go @@ -127,7 +127,7 @@ var usageTemplate = template.Must( return opt.Flag }, "prettyHeader": func(s string) string { - return cliui.Styles.Bold.Render(s) + return cliui.DefaultStyles.Bold.Render(s) }, "isEnterprise": func(opt clibase.Option) bool { return opt.Annotations.IsSet("enterprise") diff --git a/cli/list.go b/cli/list.go index 384ff923fa2f5..f5f6408c47199 100644 --- a/cli/list.go +++ b/cli/list.go @@ -98,9 +98,9 @@ func (r *RootCmd) list() *clibase.Cmd { return err } if len(res.Workspaces) == 0 { - _, _ = fmt.Fprintln(inv.Stderr, cliui.Styles.Prompt.String()+"No workspaces found! Create one:") + _, _ = fmt.Fprintln(inv.Stderr, cliui.DefaultStyles.Prompt.String()+"No workspaces found! Create one:") _, _ = fmt.Fprintln(inv.Stderr) - _, _ = fmt.Fprintln(inv.Stderr, " "+cliui.Styles.Code.Render("coder create ")) + _, _ = fmt.Fprintln(inv.Stderr, " "+cliui.DefaultStyles.Code.Render("coder create ")) _, _ = fmt.Fprintln(inv.Stderr) return nil } diff --git a/cli/login.go b/cli/login.go index 8f83b77cc5520..d4238c4d3df11 100644 --- a/cli/login.go +++ b/cli/login.go @@ -86,7 +86,7 @@ func (r *RootCmd) login() *clibase.Cmd { if err != nil { // Checking versions isn't a fatal error so we print a warning // and proceed. - _, _ = fmt.Fprintln(inv.Stderr, cliui.Styles.Warn.Render(err.Error())) + _, _ = fmt.Fprintln(inv.Stderr, cliui.DefaultStyles.Warn.Render(err.Error())) } hasInitialUser, err := client.HasFirstUser(inv.Context()) @@ -116,7 +116,7 @@ func (r *RootCmd) login() *clibase.Cmd { return xerrors.Errorf("get current user: %w", err) } username, err = cliui.Prompt(inv, cliui.PromptOptions{ - Text: "What " + cliui.Styles.Field.Render("username") + " would you like?", + Text: "What " + cliui.DefaultStyles.Field.Render("username") + " would you like?", Default: currentUser.Username, }) if errors.Is(err, cliui.Canceled) { @@ -129,7 +129,7 @@ func (r *RootCmd) login() *clibase.Cmd { if email == "" { email, err = cliui.Prompt(inv, cliui.PromptOptions{ - Text: "What's your " + cliui.Styles.Field.Render("email") + "?", + Text: "What's your " + cliui.DefaultStyles.Field.Render("email") + "?", Validate: func(s string) error { err := validator.New().Var(s, "email") if err != nil { @@ -148,7 +148,7 @@ func (r *RootCmd) login() *clibase.Cmd { for !matching { password, err = cliui.Prompt(inv, cliui.PromptOptions{ - Text: "Enter a " + cliui.Styles.Field.Render("password") + ":", + Text: "Enter a " + cliui.DefaultStyles.Field.Render("password") + ":", Secret: true, Validate: func(s string) error { return userpassword.Validate(s) @@ -158,7 +158,7 @@ func (r *RootCmd) login() *clibase.Cmd { return xerrors.Errorf("specify password prompt: %w", err) } confirm, err := cliui.Prompt(inv, cliui.PromptOptions{ - Text: "Confirm " + cliui.Styles.Field.Render("password") + ":", + Text: "Confirm " + cliui.DefaultStyles.Field.Render("password") + ":", Secret: true, Validate: cliui.ValidateNotEmpty, }) @@ -168,7 +168,7 @@ func (r *RootCmd) login() *clibase.Cmd { matching = confirm == password if !matching { - _, _ = fmt.Fprintln(inv.Stdout, cliui.Styles.Error.Render("Passwords do not match")) + _, _ = fmt.Fprintln(inv.Stdout, cliui.DefaultStyles.Error.Render("Passwords do not match")) } } } @@ -211,10 +211,10 @@ func (r *RootCmd) login() *clibase.Cmd { } _, _ = fmt.Fprintf(inv.Stdout, - cliui.Styles.Paragraph.Render(fmt.Sprintf("Welcome to Coder, %s! You're authenticated.", cliui.Styles.Keyword.Render(username)))+"\n") + cliui.DefaultStyles.Paragraph.Render(fmt.Sprintf("Welcome to Coder, %s! You're authenticated.", cliui.DefaultStyles.Keyword.Render(username)))+"\n") _, _ = fmt.Fprintf(inv.Stdout, - cliui.Styles.Paragraph.Render("Get started by creating a template: "+cliui.Styles.Code.Render("coder templates init"))+"\n") + cliui.DefaultStyles.Paragraph.Render("Get started by creating a template: "+cliui.DefaultStyles.Code.Render("coder templates init"))+"\n") return nil } @@ -264,7 +264,7 @@ func (r *RootCmd) login() *clibase.Cmd { return xerrors.Errorf("write server url: %w", err) } - _, _ = fmt.Fprintf(inv.Stdout, Caret+"Welcome to Coder, %s! You're authenticated.\n", cliui.Styles.Keyword.Render(resp.Username)) + _, _ = fmt.Fprintf(inv.Stdout, Caret+"Welcome to Coder, %s! You're authenticated.\n", cliui.DefaultStyles.Keyword.Render(resp.Username)) return nil }, } diff --git a/cli/login_test.go b/cli/login_test.go index 7e552fbe503dc..f8e24170c641e 100644 --- a/cli/login_test.go +++ b/cli/login_test.go @@ -142,7 +142,7 @@ func TestLogin(t *testing.T) { // Validate that we reprompt for matching passwords. pty.ExpectMatch("Passwords do not match") - pty.ExpectMatch("Enter a " + cliui.Styles.Field.Render("password")) + pty.ExpectMatch("Enter a " + cliui.DefaultStyles.Field.Render("password")) pty.WriteLine("SomeSecurePassword!") pty.ExpectMatch("Confirm") diff --git a/cli/ping.go b/cli/ping.go index 4ef022c7febfc..1d51b6ac0339d 100644 --- a/cli/ping.go +++ b/cli/ping.go @@ -98,14 +98,14 @@ func (r *RootCmd) ping() *clibase.Cmd { if p2p { if !didP2p { _, _ = fmt.Fprintln(inv.Stdout, "p2p connection established in", - cliui.Styles.DateTimeStamp.Render(time.Since(start).Round(time.Millisecond).String()), + cliui.DefaultStyles.DateTimeStamp.Render(time.Since(start).Round(time.Millisecond).String()), ) } didP2p = true via = fmt.Sprintf("%s via %s", - cliui.Styles.Fuchsia.Render("p2p"), - cliui.Styles.Code.Render(pong.Endpoint), + cliui.DefaultStyles.Fuchsia.Render("p2p"), + cliui.DefaultStyles.Code.Render(pong.Endpoint), ) } else { derpName := "unknown" @@ -114,15 +114,15 @@ func (r *RootCmd) ping() *clibase.Cmd { derpName = derpRegion.RegionName } via = fmt.Sprintf("%s via %s", - cliui.Styles.Fuchsia.Render("proxied"), - cliui.Styles.Code.Render(fmt.Sprintf("DERP(%s)", derpName)), + cliui.DefaultStyles.Fuchsia.Render("proxied"), + cliui.DefaultStyles.Code.Render(fmt.Sprintf("DERP(%s)", derpName)), ) } _, _ = fmt.Fprintf(inv.Stdout, "pong from %s %s in %s\n", - cliui.Styles.Keyword.Render(workspaceName), + cliui.DefaultStyles.Keyword.Render(workspaceName), via, - cliui.Styles.DateTimeStamp.Render(dur.String()), + cliui.DefaultStyles.DateTimeStamp.Render(dur.String()), ) if n == int(pingNum) { diff --git a/cli/publickey.go b/cli/publickey.go index 7d4501c9cd26e..43537eec428a1 100644 --- a/cli/publickey.go +++ b/cli/publickey.go @@ -44,13 +44,13 @@ func (r *RootCmd) publickey() *clibase.Cmd { } cliui.Infof(inv.Stdout, - "This is your public key for using "+cliui.Styles.Field.Render("git")+" in "+ + "This is your public key for using "+cliui.DefaultStyles.Field.Render("git")+" in "+ "Coder. All clones with SSH will be authenticated automatically 🪄.\n\n", ) - cliui.Infof(inv.Stdout, cliui.Styles.Code.Render(strings.TrimSpace(key.PublicKey))+"\n\n") + cliui.Infof(inv.Stdout, cliui.DefaultStyles.Code.Render(strings.TrimSpace(key.PublicKey))+"\n\n") cliui.Infof(inv.Stdout, "Add to GitHub and GitLab:"+"\n") - cliui.Infof(inv.Stdout, cliui.Styles.Prompt.String()+"https://github.com/settings/ssh/new"+"\n") - cliui.Infof(inv.Stdout, cliui.Styles.Prompt.String()+"https://gitlab.com/-/profile/keys"+"\n") + cliui.Infof(inv.Stdout, cliui.DefaultStyles.Prompt.String()+"https://github.com/settings/ssh/new"+"\n") + cliui.Infof(inv.Stdout, cliui.DefaultStyles.Prompt.String()+"https://gitlab.com/-/profile/keys"+"\n") return nil }, diff --git a/cli/rename.go b/cli/rename.go index e0443e75ed6ff..d9e2af5316603 100644 --- a/cli/rename.go +++ b/cli/rename.go @@ -27,7 +27,7 @@ func (r *RootCmd) rename() *clibase.Cmd { } _, _ = fmt.Fprintf(inv.Stdout, "%s\n\n", - cliui.Styles.Wrap.Render("WARNING: A rename can result in data loss if a resource references the workspace name in the template (e.g volumes). Please backup any data before proceeding."), + cliui.DefaultStyles.Wrap.Render("WARNING: A rename can result in data loss if a resource references the workspace name in the template (e.g volumes). Please backup any data before proceeding."), ) _, _ = fmt.Fprintf(inv.Stdout, "See: %s\n\n", "https://coder.com/docs/coder-oss/latest/templates/resource-persistence#%EF%B8%8F-persistence-pitfalls") _, err = cliui.Prompt(inv, cliui.PromptOptions{ diff --git a/cli/resetpassword.go b/cli/resetpassword.go index dcf206dd680d6..02a98993368cc 100644 --- a/cli/resetpassword.go +++ b/cli/resetpassword.go @@ -47,7 +47,7 @@ func (*RootCmd) resetPassword() *clibase.Cmd { } password, err := cliui.Prompt(inv, cliui.PromptOptions{ - Text: "Enter new " + cliui.Styles.Field.Render("password") + ":", + Text: "Enter new " + cliui.DefaultStyles.Field.Render("password") + ":", Secret: true, Validate: func(s string) error { return userpassword.Validate(s) @@ -57,7 +57,7 @@ func (*RootCmd) resetPassword() *clibase.Cmd { return xerrors.Errorf("password prompt: %w", err) } confirmedPassword, err := cliui.Prompt(inv, cliui.PromptOptions{ - Text: "Confirm " + cliui.Styles.Field.Render("password") + ":", + Text: "Confirm " + cliui.DefaultStyles.Field.Render("password") + ":", Secret: true, Validate: cliui.ValidateNotEmpty, }) @@ -81,7 +81,7 @@ func (*RootCmd) resetPassword() *clibase.Cmd { return xerrors.Errorf("updating password: %w", err) } - _, _ = fmt.Fprintf(inv.Stdout, "\nPassword has been reset for user %s!\n", cliui.Styles.Keyword.Render(user.Username)) + _, _ = fmt.Fprintf(inv.Stdout, "\nPassword has been reset for user %s!\n", cliui.DefaultStyles.Keyword.Render(user.Username)) return nil }, } diff --git a/cli/restart.go b/cli/restart.go index 51ffb2abbf871..7a139d8206bb9 100644 --- a/cli/restart.go +++ b/cli/restart.go @@ -61,7 +61,7 @@ func (r *RootCmd) restart() *clibase.Cmd { return err } - _, _ = fmt.Fprintf(out, "\nThe %s workspace has been restarted at %s!\n", cliui.Styles.Keyword.Render(workspace.Name), cliui.Styles.DateTimeStamp.Render(time.Now().Format(time.Stamp))) + _, _ = fmt.Fprintf(out, "\nThe %s workspace has been restarted at %s!\n", cliui.DefaultStyles.Keyword.Render(workspace.Name), cliui.DefaultStyles.DateTimeStamp.Render(time.Now().Format(time.Stamp))) return nil }, } diff --git a/cli/root.go b/cli/root.go index 107dfa1080437..d79f479cc3429 100644 --- a/cli/root.go +++ b/cli/root.go @@ -29,6 +29,7 @@ import ( "github.com/charmbracelet/lipgloss" "github.com/gobwas/httphead" "github.com/mattn/go-isatty" + "github.com/mitchellh/go-wordwrap" "github.com/coder/coder/buildinfo" "github.com/coder/coder/cli/clibase" @@ -42,7 +43,7 @@ import ( ) var ( - Caret = cliui.Styles.Prompt.String() + Caret = cliui.DefaultStyles.Prompt.String() // Applied as annotations to workspace commands // so they display in a separated "help" section. @@ -538,14 +539,14 @@ func (r *RootCmd) InitClient(client *codersdk.Client) clibase.MiddlewareFunc { // Just log the error here. We never want to fail a command // due to a pre-run. _, _ = fmt.Fprintf(inv.Stderr, - cliui.Styles.Warn.Render("check versions error: %s"), err) + cliui.DefaultStyles.Warn.Render("check versions error: %s"), err) _, _ = fmt.Fprintln(inv.Stderr) } if err = <-warningErr; err != nil { // Same as above _, _ = fmt.Fprintf(inv.Stderr, - cliui.Styles.Warn.Render("check entitlement warnings error: %s"), err) + cliui.DefaultStyles.Warn.Render("check entitlement warnings error: %s"), err) _, _ = fmt.Fprintln(inv.Stderr) } @@ -676,17 +677,20 @@ type example struct { // formatExamples formats the examples as width wrapped bulletpoint // descriptions with the command underneath. func formatExamples(examples ...example) string { - wrap := cliui.Styles.Wrap.Copy() - wrap.PaddingLeft(4) var sb strings.Builder + + padStyle := cliui.DefaultStyles.Wrap.Copy().PaddingLeft(4) for i, e := range examples { if len(e.Description) > 0 { - _, _ = sb.WriteString(" - " + wrap.Render(e.Description + ":")[4:] + "\n\n ") + wordwrap.WrapString(e.Description, 80) + _, _ = sb.WriteString( + " - " + padStyle.Render(e.Description + ":")[4:] + "\n\n ", + ) } // We add 1 space here because `cliui.Styles.Code` adds an extra // space. This makes the code block align at an even 2 or 6 // spaces for symmetry. - _, _ = sb.WriteString(" " + cliui.Styles.Code.Render(fmt.Sprintf("$ %s", e.Command))) + _, _ = sb.WriteString(" " + cliui.DefaultStyles.Code.Render(fmt.Sprintf("$ %s", e.Command))) if i < len(examples)-1 { _, _ = sb.WriteString("\n\n") } @@ -724,7 +728,7 @@ func (r *RootCmd) checkVersions(i *clibase.Invocation, client *codersdk.Client) } if !buildinfo.VersionsMatch(clientVersion, info.Version) { - warn := cliui.Styles.Warn.Copy().Align(lipgloss.Left) + warn := cliui.DefaultStyles.Warn.Copy().Align(lipgloss.Left) _, _ = fmt.Fprintf(i.Stderr, warn.Render(fmtWarningText), clientVersion, info.Version, strings.TrimPrefix(info.CanonicalVersion(), "v")) _, _ = fmt.Fprintln(i.Stderr) } @@ -743,7 +747,7 @@ func (r *RootCmd) checkWarnings(i *clibase.Invocation, client *codersdk.Client) entitlements, err := client.Entitlements(ctx) if err == nil { for _, w := range entitlements.Warnings { - _, _ = fmt.Fprintln(i.Stderr, cliui.Styles.Warn.Render(w)) + _, _ = fmt.Fprintln(i.Stderr, cliui.DefaultStyles.Warn.Render(w)) } } return nil diff --git a/cli/server.go b/cli/server.go index 61368f16fbd78..d7dea720978e9 100644 --- a/cli/server.go +++ b/cli/server.go @@ -361,7 +361,7 @@ func (r *RootCmd) Server(newAPI func(context.Context, *coderd.Options) (*coderd. cliui.Warnf( inv.Stderr, "The access URL %s %s, this may cause unexpected problems when creating workspaces. Generate a unique *.try.coder.app URL by not specifying an access URL.\n", - cliui.Styles.Field.Render(cfg.AccessURL.String()), reason, + cliui.DefaultStyles.Field.Render(cfg.AccessURL.String()), reason, ) } @@ -904,7 +904,7 @@ func (r *RootCmd) Server(newAPI func(context.Context, *coderd.Options) (*coderd. select { case <-notifyCtx.Done(): exitErr = notifyCtx.Err() - _, _ = fmt.Fprintln(inv.Stdout, cliui.Styles.Bold.Render( + _, _ = fmt.Fprintln(inv.Stdout, cliui.DefaultStyles.Bold.Render( "Interrupt caught, gracefully exiting. Use ctrl+\\ to force quit", )) case <-tunnelDone: @@ -1016,7 +1016,7 @@ func (r *RootCmd) Server(newAPI func(context.Context, *coderd.Options) (*coderd. if pgRawURL { _, _ = fmt.Fprintf(inv.Stdout, "%s\n", url) } else { - _, _ = fmt.Fprintf(inv.Stdout, "%s\n", cliui.Styles.Code.Render(fmt.Sprintf("psql %q", url))) + _, _ = fmt.Fprintf(inv.Stdout, "%s\n", cliui.DefaultStyles.Code.Render(fmt.Sprintf("psql %q", url))) } return nil }, @@ -1046,7 +1046,7 @@ func (r *RootCmd) Server(newAPI func(context.Context, *coderd.Options) (*coderd. if pgRawURL { _, _ = fmt.Fprintf(inv.Stdout, "%s\n", url) } else { - _, _ = fmt.Fprintf(inv.Stdout, "%s\n", cliui.Styles.Code.Render(fmt.Sprintf("psql %q", url))) + _, _ = fmt.Fprintf(inv.Stdout, "%s\n", cliui.DefaultStyles.Code.Render(fmt.Sprintf("psql %q", url))) } <-ctx.Done() @@ -1282,7 +1282,7 @@ func PrintLogo(inv *clibase.Invocation) { return } - _, _ = fmt.Fprintf(inv.Stdout, "%s - Your Self-Hosted Remote Development Platform\n", cliui.Styles.Bold.Render("Coder "+buildinfo.Version())) + _, _ = fmt.Fprintf(inv.Stdout, "%s - Your Self-Hosted Remote Development Platform\n", cliui.DefaultStyles.Bold.Render("Coder "+buildinfo.Version())) } func loadCertificates(tlsCertFiles, tlsKeyFiles []string) ([]tls.Certificate, error) { diff --git a/cli/start.go b/cli/start.go index 6ce6093afe774..1fb619abf4b77 100644 --- a/cli/start.go +++ b/cli/start.go @@ -39,7 +39,7 @@ func (r *RootCmd) start() *clibase.Cmd { return err } - _, _ = fmt.Fprintf(inv.Stdout, "\nThe %s workspace has been started at %s!\n", cliui.Styles.Keyword.Render(workspace.Name), cliui.Styles.DateTimeStamp.Render(time.Now().Format(time.Stamp))) + _, _ = fmt.Fprintf(inv.Stdout, "\nThe %s workspace has been started at %s!\n", cliui.DefaultStyles.Keyword.Render(workspace.Name), cliui.DefaultStyles.DateTimeStamp.Render(time.Now().Format(time.Stamp))) return nil }, } diff --git a/cli/stop.go b/cli/stop.go index 442b6b662ea8b..1dbf446ed2979 100644 --- a/cli/stop.go +++ b/cli/stop.go @@ -47,7 +47,7 @@ func (r *RootCmd) stop() *clibase.Cmd { return err } - _, _ = fmt.Fprintf(inv.Stdout, "\nThe %s workspace has been stopped at %s!\n", cliui.Styles.Keyword.Render(workspace.Name), cliui.Styles.DateTimeStamp.Render(time.Now().Format(time.Stamp))) + _, _ = fmt.Fprintf(inv.Stdout, "\nThe %s workspace has been stopped at %s!\n", cliui.DefaultStyles.Keyword.Render(workspace.Name), cliui.DefaultStyles.DateTimeStamp.Render(time.Now().Format(time.Stamp))) return nil }, } diff --git a/cli/templatecreate.go b/cli/templatecreate.go index 47b3953df1226..a49997c3315ab 100644 --- a/cli/templatecreate.go +++ b/cli/templatecreate.go @@ -133,11 +133,11 @@ func (r *RootCmd) templateCreate() *clibase.Cmd { return err } - _, _ = fmt.Fprintln(inv.Stdout, "\n"+cliui.Styles.Wrap.Render( - "The "+cliui.Styles.Keyword.Render(templateName)+" template has been created at "+cliui.Styles.DateTimeStamp.Render(time.Now().Format(time.Stamp))+"! "+ + _, _ = fmt.Fprintln(inv.Stdout, "\n"+cliui.DefaultStyles.Wrap.Render( + "The "+cliui.DefaultStyles.Keyword.Render(templateName)+" template has been created at "+cliui.DefaultStyles.DateTimeStamp.Render(time.Now().Format(time.Stamp))+"! "+ "Developers can provision a workspace with this template using:")+"\n") - _, _ = fmt.Fprintln(inv.Stdout, " "+cliui.Styles.Code.Render(fmt.Sprintf("coder create --template=%q [workspace name]", templateName))) + _, _ = fmt.Fprintln(inv.Stdout, " "+cliui.DefaultStyles.Code.Render(fmt.Sprintf("coder create --template=%q [workspace name]", templateName))) _, _ = fmt.Fprintln(inv.Stdout) return nil diff --git a/cli/templatedelete.go b/cli/templatedelete.go index 4833362861489..d954dbf44c081 100644 --- a/cli/templatedelete.go +++ b/cli/templatedelete.go @@ -77,7 +77,7 @@ func (r *RootCmd) templateDelete() *clibase.Cmd { // Confirm deletion of the template. _, err = cliui.Prompt(inv, cliui.PromptOptions{ - Text: fmt.Sprintf("Delete these templates: %s?", cliui.Styles.Code.Render(strings.Join(templateNames, ", "))), + Text: fmt.Sprintf("Delete these templates: %s?", cliui.DefaultStyles.Code.Render(strings.Join(templateNames, ", "))), IsConfirm: true, Default: cliui.ConfirmNo, }) @@ -91,7 +91,7 @@ func (r *RootCmd) templateDelete() *clibase.Cmd { return xerrors.Errorf("delete template %q: %w", template.Name, err) } - _, _ = fmt.Fprintln(inv.Stdout, "Deleted template "+cliui.Styles.Code.Render(template.Name)+" at "+cliui.Styles.DateTimeStamp.Render(time.Now().Format(time.Stamp))+"!") + _, _ = fmt.Fprintln(inv.Stdout, "Deleted template "+cliui.DefaultStyles.Code.Render(template.Name)+" at "+cliui.DefaultStyles.DateTimeStamp.Render(time.Now().Format(time.Stamp))+"!") } return nil diff --git a/cli/templatedelete_test.go b/cli/templatedelete_test.go index 5c029be96fb5e..1f7c032b11d59 100644 --- a/cli/templatedelete_test.go +++ b/cli/templatedelete_test.go @@ -37,7 +37,7 @@ func TestTemplateDelete(t *testing.T) { execDone <- inv.Run() }() - pty.ExpectMatch(fmt.Sprintf("Delete these templates: %s?", cliui.Styles.Code.Render(template.Name))) + pty.ExpectMatch(fmt.Sprintf("Delete these templates: %s?", cliui.DefaultStyles.Code.Render(template.Name))) pty.WriteLine("yes") require.NoError(t, <-execDone) @@ -95,7 +95,7 @@ func TestTemplateDelete(t *testing.T) { execDone <- inv.Run() }() - pty.ExpectMatch(fmt.Sprintf("Delete these templates: %s?", cliui.Styles.Code.Render(strings.Join(templateNames, ", ")))) + pty.ExpectMatch(fmt.Sprintf("Delete these templates: %s?", cliui.DefaultStyles.Code.Render(strings.Join(templateNames, ", ")))) pty.WriteLine("yes") require.NoError(t, <-execDone) diff --git a/cli/templateedit.go b/cli/templateedit.go index 97bc3e13271a3..53818e86b33b5 100644 --- a/cli/templateedit.go +++ b/cli/templateedit.go @@ -90,7 +90,7 @@ func (r *RootCmd) templateEdit() *clibase.Cmd { if err != nil { return xerrors.Errorf("update template metadata: %w", err) } - _, _ = fmt.Fprintf(inv.Stdout, "Updated template metadata at %s!\n", cliui.Styles.DateTimeStamp.Render(time.Now().Format(time.Stamp))) + _, _ = fmt.Fprintf(inv.Stdout, "Updated template metadata at %s!\n", cliui.DefaultStyles.DateTimeStamp.Render(time.Now().Format(time.Stamp))) return nil }, } diff --git a/cli/templateinit.go b/cli/templateinit.go index 82ec3f845b846..b42e555fde074 100644 --- a/cli/templateinit.go +++ b/cli/templateinit.go @@ -42,15 +42,15 @@ func (*RootCmd) templateInit() *clibase.Cmd { for _, example := range exampleList { name := fmt.Sprintf( "%s\n%s\n%s\n", - cliui.Styles.Bold.Render(example.Name), - cliui.Styles.Wrap.Copy().PaddingLeft(6).Render(example.Description), - cliui.Styles.Keyword.Copy().PaddingLeft(6).Render(example.URL), + cliui.DefaultStyles.Bold.Render(example.Name), + cliui.DefaultStyles.Wrap.Copy().PaddingLeft(6).Render(example.Description), + cliui.DefaultStyles.Keyword.Copy().PaddingLeft(6).Render(example.URL), ) optsToID[name] = example.ID } opts := maps.Keys(optsToID) sort.Strings(opts) - _, _ = fmt.Fprintln(inv.Stdout, cliui.Styles.Wrap.Render( + _, _ = fmt.Fprintln(inv.Stdout, cliui.DefaultStyles.Wrap.Render( "A template defines infrastructure as code to be provisioned "+ "for individual developer workspaces. Select an example to be copied to the active directory:\n")) selected, err := cliui.Select(inv, cliui.SelectOptions{ @@ -94,7 +94,7 @@ func (*RootCmd) templateInit() *clibase.Cmd { } else { relPath = "./" + relPath } - _, _ = fmt.Fprintf(inv.Stdout, "Extracting %s to %s...\n", cliui.Styles.Field.Render(selectedTemplate.ID), relPath) + _, _ = fmt.Fprintf(inv.Stdout, "Extracting %s to %s...\n", cliui.DefaultStyles.Field.Render(selectedTemplate.ID), relPath) err = os.MkdirAll(directory, 0o700) if err != nil { return err @@ -104,8 +104,8 @@ func (*RootCmd) templateInit() *clibase.Cmd { return err } _, _ = fmt.Fprintln(inv.Stdout, "Create your template by running:") - _, _ = fmt.Fprintln(inv.Stdout, cliui.Styles.Paragraph.Render(cliui.Styles.Code.Render("cd "+relPath+" && coder templates create"))+"\n") - _, _ = fmt.Fprintln(inv.Stdout, cliui.Styles.Wrap.Render("Examples provide a starting point and are expected to be edited! 🎨")) + _, _ = fmt.Fprintln(inv.Stdout, cliui.DefaultStyles.Paragraph.Render(cliui.DefaultStyles.Code.Render("cd "+relPath+" && coder templates create"))+"\n") + _, _ = fmt.Fprintln(inv.Stdout, cliui.DefaultStyles.Wrap.Render("Examples provide a starting point and are expected to be edited! 🎨")) return nil }, } diff --git a/cli/templatepush.go b/cli/templatepush.go index 684eac23e3e66..29201b8510b9f 100644 --- a/cli/templatepush.go +++ b/cli/templatepush.go @@ -73,7 +73,7 @@ func (pf *templateUploadFlags) upload(inv *clibase.Invocation, client *codersdk. spin := spinner.New(spinner.CharSets[5], 100*time.Millisecond) spin.Writer = inv.Stdout - spin.Suffix = cliui.Styles.Keyword.Render(" Uploading directory...") + spin.Suffix = cliui.DefaultStyles.Keyword.Render(" Uploading directory...") spin.Start() defer spin.Stop() @@ -182,7 +182,7 @@ func (r *RootCmd) templatePush() *clibase.Cmd { } } - _, _ = fmt.Fprintf(inv.Stdout, "Updated version at %s!\n", cliui.Styles.DateTimeStamp.Render(time.Now().Format(time.Stamp))) + _, _ = fmt.Fprintf(inv.Stdout, "Updated version at %s!\n", cliui.DefaultStyles.DateTimeStamp.Render(time.Now().Format(time.Stamp))) return nil }, } diff --git a/cli/templates.go b/cli/templates.go index 229ee2809b004..ad347a138ba91 100644 --- a/cli/templates.go +++ b/cli/templates.go @@ -76,7 +76,7 @@ func templatesToRows(templates ...codersdk.Template) []templateTableRow { OrganizationID: template.OrganizationID, Provisioner: template.Provisioner, ActiveVersionID: template.ActiveVersionID, - UsedBy: cliui.Styles.Fuchsia.Render(formatActiveDevelopers(template.ActiveUserCount)), + UsedBy: cliui.DefaultStyles.Fuchsia.Render(formatActiveDevelopers(template.ActiveUserCount)), DefaultTTL: (time.Duration(template.DefaultTTLMillis) * time.Millisecond), } } diff --git a/cli/templateversions.go b/cli/templateversions.go index 0eca03d2a5245..2fdc43e240595 100644 --- a/cli/templateversions.go +++ b/cli/templateversions.go @@ -101,7 +101,7 @@ func templateVersionsToRows(activeVersionID uuid.UUID, templateVersions ...coder for i, templateVersion := range templateVersions { activeStatus := "" if templateVersion.ID == activeVersionID { - activeStatus = cliui.Styles.Code.Render(cliui.Styles.Keyword.Render("Active")) + activeStatus = cliui.DefaultStyles.Code.Render(cliui.DefaultStyles.Keyword.Render("Active")) } rows[i] = templateVersionRow{ diff --git a/cli/usercreate.go b/cli/usercreate.go index f59b6e3bec935..eac6cc9e84bd8 100644 --- a/cli/usercreate.go +++ b/cli/usercreate.go @@ -71,16 +71,16 @@ func (r *RootCmd) userCreate() *clibase.Cmd { } _, _ = fmt.Fprintln(inv.Stderr, `A new user has been created! Share the instructions below to get them started. -`+cliui.Styles.Placeholder.Render("—————————————————————————————————————————————————")+` +`+cliui.DefaultStyles.Placeholder.Render("—————————————————————————————————————————————————")+` Download the Coder command line for your operating system: https://github.com/coder/coder/releases -Run `+cliui.Styles.Code.Render("coder login "+client.URL.String())+` to authenticate. +Run `+cliui.DefaultStyles.Code.Render("coder login "+client.URL.String())+` to authenticate. -Your email is: `+cliui.Styles.Field.Render(email)+` -Your password is: `+cliui.Styles.Field.Render(password)+` +Your email is: `+cliui.DefaultStyles.Field.Render(email)+` +Your password is: `+cliui.DefaultStyles.Field.Render(password)+` -Create a workspace `+cliui.Styles.Code.Render("coder create")+`!`) +Create a workspace `+cliui.DefaultStyles.Code.Render("coder create")+`!`) return nil }, } diff --git a/cli/userstatus.go b/cli/userstatus.go index e769bf0e1b986..6a2ada1a7cd19 100644 --- a/cli/userstatus.go +++ b/cli/userstatus.go @@ -89,7 +89,7 @@ func (r *RootCmd) createUserStatusCommand(sdkStatus codersdk.UserStatus) *clibas return xerrors.Errorf("%s user: %w", verb, err) } - _, _ = fmt.Fprintf(inv.Stdout, "\nUser %s has been %s!\n", cliui.Styles.Keyword.Render(user.Username), pastVerb) + _, _ = fmt.Fprintf(inv.Stdout, "\nUser %s has been %s!\n", cliui.DefaultStyles.Keyword.Render(user.Username), pastVerb) return nil }, } diff --git a/cli/version.go b/cli/version.go index 9be348257d861..fb33749f004f9 100644 --- a/cli/version.go +++ b/cli/version.go @@ -35,9 +35,9 @@ func (vi versionInfo) String() string { _, _ = str.WriteString("\r\n" + vi.ExternalURL + "\r\n\r\n") if vi.Slim { - _, _ = str.WriteString(fmt.Sprintf("Slim build of Coder, does not support the %s subcommand.", cliui.Styles.Code.Render("server"))) + _, _ = str.WriteString(fmt.Sprintf("Slim build of Coder, does not support the %s subcommand.", cliui.DefaultStyles.Code.Render("server"))) } else { - _, _ = str.WriteString(fmt.Sprintf("Full build of Coder, supports the %s subcommand.", cliui.Styles.Code.Render("server"))) + _, _ = str.WriteString(fmt.Sprintf("Full build of Coder, supports the %s subcommand.", cliui.DefaultStyles.Code.Render("server"))) } return str.String() } diff --git a/cmd/cliui/main.go b/cmd/cliui/main.go index 18129d1bf64d0..ccbff650d2e09 100644 --- a/cmd/cliui/main.go +++ b/cmd/cliui/main.go @@ -29,7 +29,7 @@ func main() { Use: "prompt", Handler: func(inv *clibase.Invocation) error { _, err := cliui.Prompt(inv, cliui.PromptOptions{ - Text: "What is our " + cliui.Styles.Field.Render("company name") + "?", + Text: "What is our " + cliui.DefaultStyles.Field.Render("company name") + "?", Default: "acme-corp", Validate: func(s string) error { if !strings.EqualFold(s, "coder") { diff --git a/coderd/devtunnel/tunnel.go b/coderd/devtunnel/tunnel.go index 42f4ae4225e94..11bbc7dad6bee 100644 --- a/coderd/devtunnel/tunnel.go +++ b/coderd/devtunnel/tunnel.go @@ -114,8 +114,8 @@ func readOrGenerateConfig(customTunnelHost string) (Config, error) { if cfg.Version == 0 { _, _ = fmt.Println() - _, _ = fmt.Println(cliui.Styles.Error.Render("You're running a deprecated tunnel version!")) - _, _ = fmt.Println(cliui.Styles.Error.Render("Upgrading you to the new version now. You will need to rebuild running workspaces.")) + _, _ = fmt.Println(cliui.DefaultStyles.Error.Render("You're running a deprecated tunnel version!")) + _, _ = fmt.Println(cliui.DefaultStyles.Error.Render("Upgrading you to the new version now. You will need to rebuild running workspaces.")) _, _ = fmt.Println() cfg, err := GenerateConfig(customTunnelHost) @@ -172,8 +172,8 @@ func GenerateConfig(customTunnelHost string) (Config, error) { spin.Stop() _, _ = fmt.Printf("Using tunnel in %s with latency %s.\n", - cliui.Styles.Keyword.Render(locationName), - cliui.Styles.Code.Render(node.AvgLatency.String()), + cliui.DefaultStyles.Keyword.Render(locationName), + cliui.DefaultStyles.Code.Render(node.AvgLatency.String()), ) return Config{ diff --git a/enterprise/cli/groupcreate.go b/enterprise/cli/groupcreate.go index 21398566e1a96..c7c63d469ad0c 100644 --- a/enterprise/cli/groupcreate.go +++ b/enterprise/cli/groupcreate.go @@ -37,7 +37,7 @@ func (r *RootCmd) groupCreate() *clibase.Cmd { return xerrors.Errorf("create group: %w", err) } - _, _ = fmt.Fprintf(inv.Stdout, "Successfully created group %s!\n", cliui.Styles.Keyword.Render(group.Name)) + _, _ = fmt.Fprintf(inv.Stdout, "Successfully created group %s!\n", cliui.DefaultStyles.Keyword.Render(group.Name)) return nil }, } diff --git a/enterprise/cli/groupcreate_test.go b/enterprise/cli/groupcreate_test.go index 639d7ecc75d65..5b625f1a1e500 100644 --- a/enterprise/cli/groupcreate_test.go +++ b/enterprise/cli/groupcreate_test.go @@ -46,6 +46,6 @@ func TestCreateGroup(t *testing.T) { err := inv.Run() require.NoError(t, err) - pty.ExpectMatch(fmt.Sprintf("Successfully created group %s!", cliui.Styles.Keyword.Render(groupName))) + pty.ExpectMatch(fmt.Sprintf("Successfully created group %s!", cliui.DefaultStyles.Keyword.Render(groupName))) }) } diff --git a/enterprise/cli/groupdelete.go b/enterprise/cli/groupdelete.go index 63f0ae9d8c90a..268d8064df310 100644 --- a/enterprise/cli/groupdelete.go +++ b/enterprise/cli/groupdelete.go @@ -41,7 +41,7 @@ func (r *RootCmd) groupDelete() *clibase.Cmd { return xerrors.Errorf("delete group: %w", err) } - _, _ = fmt.Fprintf(inv.Stdout, "Successfully deleted group %s!\n", cliui.Styles.Keyword.Render(group.Name)) + _, _ = fmt.Fprintf(inv.Stdout, "Successfully deleted group %s!\n", cliui.DefaultStyles.Keyword.Render(group.Name)) return nil }, } diff --git a/enterprise/cli/groupdelete_test.go b/enterprise/cli/groupdelete_test.go index 93a81f467db23..b9a9ce413e39f 100644 --- a/enterprise/cli/groupdelete_test.go +++ b/enterprise/cli/groupdelete_test.go @@ -49,7 +49,7 @@ func TestGroupDelete(t *testing.T) { err = inv.Run() require.NoError(t, err) - pty.ExpectMatch(fmt.Sprintf("Successfully deleted group %s", cliui.Styles.Keyword.Render(group.Name))) + pty.ExpectMatch(fmt.Sprintf("Successfully deleted group %s", cliui.DefaultStyles.Keyword.Render(group.Name))) }) t.Run("NoArg", func(t *testing.T) { diff --git a/enterprise/cli/groupedit.go b/enterprise/cli/groupedit.go index 7e3d381252b96..0b8abae1dad0e 100644 --- a/enterprise/cli/groupedit.go +++ b/enterprise/cli/groupedit.go @@ -72,7 +72,7 @@ func (r *RootCmd) groupEdit() *clibase.Cmd { return xerrors.Errorf("patch group: %w", err) } - _, _ = fmt.Fprintf(inv.Stdout, "Successfully patched group %s!\n", cliui.Styles.Keyword.Render(group.Name)) + _, _ = fmt.Fprintf(inv.Stdout, "Successfully patched group %s!\n", cliui.DefaultStyles.Keyword.Render(group.Name)) return nil }, } diff --git a/enterprise/cli/groupedit_test.go b/enterprise/cli/groupedit_test.go index 06e693ae0eef6..bf446c81e0eb5 100644 --- a/enterprise/cli/groupedit_test.go +++ b/enterprise/cli/groupedit_test.go @@ -68,7 +68,7 @@ func TestGroupEdit(t *testing.T) { err = inv.Run() require.NoError(t, err) - pty.ExpectMatch(fmt.Sprintf("Successfully patched group %s", cliui.Styles.Keyword.Render(expectedName))) + pty.ExpectMatch(fmt.Sprintf("Successfully patched group %s", cliui.DefaultStyles.Keyword.Render(expectedName))) }) t.Run("InvalidUserInput", func(t *testing.T) { diff --git a/enterprise/cli/provisionerdaemons.go b/enterprise/cli/provisionerdaemons.go index 8a6b13b5af9dd..03892fa37f65c 100644 --- a/enterprise/cli/provisionerdaemons.go +++ b/enterprise/cli/provisionerdaemons.go @@ -125,7 +125,7 @@ func (r *RootCmd) provisionerDaemonStart() *clibase.Cmd { select { case <-notifyCtx.Done(): exitErr = notifyCtx.Err() - _, _ = fmt.Fprintln(inv.Stdout, cliui.Styles.Bold.Render( + _, _ = fmt.Fprintln(inv.Stdout, cliui.DefaultStyles.Bold.Render( "Interrupt caught, gracefully exiting. Use ctrl+\\ to force quit", )) case exitErr = <-errCh: diff --git a/enterprise/cli/proxyserver.go b/enterprise/cli/proxyserver.go index d4a1de57c6986..c043951ca5431 100644 --- a/enterprise/cli/proxyserver.go +++ b/enterprise/cli/proxyserver.go @@ -185,7 +185,7 @@ func (*RootCmd) proxyServer() *clibase.Cmd { cliui.Warnf( inv.Stderr, "The access URL %s %s, this may cause unexpected problems when creating workspaces. Generate a unique *.try.coder.app URL by not specifying an access URL.\n", - cliui.Styles.Field.Render(cfg.AccessURL.String()), reason, + cliui.DefaultStyles.Field.Render(cfg.AccessURL.String()), reason, ) } @@ -297,7 +297,7 @@ func (*RootCmd) proxyServer() *clibase.Cmd { case exitErr = <-errCh: case <-notifyCtx.Done(): exitErr = notifyCtx.Err() - _, _ = fmt.Fprintln(inv.Stdout, cliui.Styles.Bold.Render( + _, _ = fmt.Fprintln(inv.Stdout, cliui.DefaultStyles.Bold.Render( "Interrupt caught, gracefully exiting. Use ctrl+\\ to force quit", )) } diff --git a/enterprise/cmd/coder/main.go b/enterprise/cmd/coder/main.go index 0fc0e6a4ea680..b44275e3696a5 100644 --- a/enterprise/cmd/coder/main.go +++ b/enterprise/cmd/coder/main.go @@ -8,6 +8,5 @@ import ( func main() { var rootCmd entcli.RootCmd - rootCmd.RunMain(rootCmd.EnterpriseSubcommands()) }