package main import ( "fmt" "regexp" "strings" "github.com/charmbracelet/vhs/parser" "github.com/charmbracelet/vhs/token" "github.com/mattn/go-runewidth" ) const sourceDisplayMaxLength = 10 // Highlight syntax highlights a command for prettier printing. // It takes an argument whether or not to print the command in a faint style to // represent hidden commands. func Highlight(c parser.Command, faint bool) string { var ( optionsStyle = TimeStyle argsStyle = NumberStyle ) sourcePrefix := "" if c.Source != "" { displayPath := runewidth.Truncate(strings.TrimSuffix(c.Source, extension), sourceDisplayMaxLength, "…") sourcePrefix = GrayStyle.Render(displayPath+":") + " " } if faint { if c.Options != "" { return sourcePrefix + FaintStyle.Render(fmt.Sprintf("%s %s %s", c.Type, c.Options, c.Args)) } return sourcePrefix + FaintStyle.Render(fmt.Sprintf("%s %s", c.Type, c.Args)) } switch c.Type { case token.REGEX: argsStyle = StringStyle case token.SET: optionsStyle = KeywordStyle if isNumber(c.Args) { argsStyle = NumberStyle } else if isTime(c.Args) { argsStyle = TimeStyle } else { argsStyle = StringStyle } case token.ENV: optionsStyle = NoneStyle argsStyle = StringStyle case token.OUTPUT: optionsStyle = NoneStyle argsStyle = StringStyle case token.CTRL: argsStyle = CommandStyle case token.SLEEP: argsStyle = TimeStyle case token.TYPE: optionsStyle = TimeStyle argsStyle = StringStyle case token.HIDE, token.SHOW: return FaintStyle.Render(c.Type.String()) } var s strings.Builder s.WriteString(sourcePrefix) s.WriteString(CommandStyle.Render(c.Type.String()) + " ") if c.Options != "" { s.WriteString(optionsStyle.Render(c.Options)) switch c.Type { case token.ENV: s.WriteString("=") default: s.WriteString(" ") } } s.WriteString(argsStyle.Render(c.Args)) return s.String() } var numberRegex = regexp.MustCompile("^[0-9]+$") func isNumber(s string) bool { return numberRegex.MatchString(s) } var timeRegex = regexp.MustCompile("^[0-9]+m?s$") func isTime(s string) bool { return timeRegex.MatchString(s) }