// scanBarFactory returns a progress bar function to report URL scanning. func scanBarFactory(prefix string) scanBarFunc { prevLineSize := 0 fileCount := 0 termSize, err := ts.GetSize() if err != nil { fatalIf(probe.NewError(err), "Unable to get terminal size.") } termWidth := termSize.Col() cursorCh := cursorAnimate() return func(source string) { scanPrefix := fmt.Sprintf("[%s] %s ", humanize.Comma(int64(fileCount)), string(<-cursorCh)) if prefix != "" { scanPrefix = fmt.Sprintf("Scanning %s [%s] %s ", prefix, humanize.Comma(int64(fileCount)), string(<-cursorCh)) } if prevLineSize != 0 { // erase previous line console.PrintC("\r" + scanPrefix + strings.Repeat(" ", prevLineSize-len([]rune(scanPrefix)))) } source = fixateScanBar(source, termWidth-len([]rune(scanPrefix))-1) barText := "\r" + scanPrefix + source console.PrintC(barText) prevLineSize = len([]rune(barText)) fileCount++ } }
// scanBarFactory returns a progress bar function to report URL scanning. func scanBarFactory() scanBarFunc { prevLineSize := 0 prevSource := "" fileCount := 0 termSize, err := ts.GetSize() if err != nil { fatalIf(probe.NewError(err), "Unable to get terminal size. Please use --quiet option.") } termWidth := termSize.Col() cursorCh := cursorAnimate() return func(source string) { scanPrefix := fmt.Sprintf("[%s] %s ", humanize.Comma(int64(fileCount)), string(<-cursorCh)) cmnPrefix := commonPrefix(source, prevSource) eraseLen := prevLineSize - len([]rune(scanPrefix+cmnPrefix)) if eraseLen < 1 { eraseLen = 0 } if prevLineSize != 0 { // erase previous line console.PrintC("\r" + scanPrefix + cmnPrefix + strings.Repeat(" ", eraseLen)) } source = fixateScanBar(source, termWidth-len([]rune(scanPrefix))-1) barText := scanPrefix + source console.PrintC("\r" + barText) prevSource = source prevLineSize = len([]rune(barText)) fileCount++ } }
func (p *ProgressMeter) update() { if p.dryRun || (p.estimatedFiles == 0 && p.skippedFiles == 0) { return } width := 80 // default to 80 chars wide if ts.GetSize() fails size, err := ts.GetSize() if err == nil { width = size.Col() } // (%d of %d files, %d skipped) %f B / %f B, %f B skipped // skipped counts only show when > 0 out := fmt.Sprintf("\rGit LFS: (%d of %d files", p.finishedFiles, p.estimatedFiles) if p.skippedFiles > 0 { out += fmt.Sprintf(", %d skipped", p.skippedFiles) } out += fmt.Sprintf(") %s / %s", formatBytes(p.currentBytes), formatBytes(p.estimatedBytes)) if p.skippedBytes > 0 { out += fmt.Sprintf(", %s skipped", formatBytes(p.skippedBytes)) } padlen := width - len(out) if 0 < padlen { out += strings.Repeat(" ", padlen) } fmt.Fprintf(os.Stdout, out) }
// colorizeUpdateMessage - inspired from Yeoman project npm package https://github.com/yeoman/update-notifier func colorizeUpdateMessage(updateString string) (string, *probe.Error) { // TODO - make this configurable // // initialize coloring blue := color.New(color.FgBlue, color.Bold).SprintFunc() yellow := color.New(color.FgYellow, color.Bold).SprintfFunc() // calculate length without color coding, due to ANSI color characters padded to actual // string the final length is wrong than the original string length line1Str := fmt.Sprintf(" Update available: ") line2Str := fmt.Sprintf(" Run \"%s\" to update. ", updateString) line1Length := len(line1Str) line2Length := len(line2Str) // populate lines with color coding line1InColor := line1Str line2InColor := fmt.Sprintf(" Run \"%s\" to update. ", blue(updateString)) // calculate the rectangular box size maxContentWidth := int(math.Max(float64(line1Length), float64(line2Length))) line1Rest := maxContentWidth - line1Length line2Rest := maxContentWidth - line2Length terminal, err := ts.GetSize() if err != nil { return "", probe.NewError(err) } var message string switch { case len(line2Str) > terminal.Col(): message = "\n" + line1InColor + "\n" + line2InColor + "\n" default: // on windows terminal turn off unicode characters var top, bottom, sideBar string if runtime.GOOS == "windows" { top = yellow("*" + strings.Repeat("*", maxContentWidth) + "*") bottom = yellow("*" + strings.Repeat("*", maxContentWidth) + "*") sideBar = yellow("|") } else { // color the rectangular box, use unicode characters here top = yellow("┏" + strings.Repeat("━", maxContentWidth) + "┓") bottom = yellow("┗" + strings.Repeat("━", maxContentWidth) + "┛") sideBar = yellow("┃") } // fill spaces to the rest of the area spacePaddingLine1 := strings.Repeat(" ", line1Rest) spacePaddingLine2 := strings.Repeat(" ", line2Rest) // construct the final message message = "\n" + top + "\n" + sideBar + line1InColor + spacePaddingLine1 + sideBar + "\n" + sideBar + line2InColor + spacePaddingLine2 + sideBar + "\n" + bottom + "\n" } // finally print the message return message, nil }
func (s *Spinner) update(out io.Writer, prefix, msg string) { str := fmt.Sprintf("%v %v", prefix, msg) width := 80 // default to 80 chars wide if ts.GetSize() fails size, err := ts.GetSize() if err == nil { width = size.Col() } padding := strings.Repeat(" ", width-len(str)) fmt.Fprintf(out, "\r%v%v", str, padding) }
func getColumns(widthstr string) int { numstr := "" format := "" if strings.HasSuffix(widthstr, "%") { if len(widthstr) < 2 { fmt.Fprintf(os.Stderr, "Invalid percentage.\n") os.Exit(1) } numstr = widthstr[:len(widthstr)-1] format = "percent" } else if strings.Contains(widthstr, ".") { numstr = widthstr format = "decimal" } else { numstr = widthstr format = "columns" } num := 0 if format == "decimal" { f, err := strconv.ParseFloat(numstr, 64) handleErr(err) num = int(100.0 * f) } else { var err error num, err = strconv.Atoi(numstr) handleErr(err) } if format == "columns" && num > 0 { return num } size, err := ts.GetSize() if err != nil { fmt.Fprintln(os.Stderr, "Can't get terminal size.\n"+ "You may need to set width manually using -w num") os.Exit(2) } if format == "columns" { return size.Col() } cols := float64(size.Col()) return int(cols * (float64(num) / 100.0)) }
func main() { app := registerApp() app.Before = registerBefore app.ExtraInfo = func() map[string]string { if _, e := ts.GetSize(); e != nil { globalQuietFlag = true } if globalDebugFlag { return getSystemData() } return make(map[string]string) } app.RunAndExitOnError() }
// colorizeMessage - inspired from Yeoman project npm package https://github.com/yeoman/update-notifier func colorizeMessage(message string) string { // initialize coloring cyan := color.New(color.FgCyan, color.Bold).SprintFunc() yellow := color.New(color.FgYellow, color.Bold).SprintfFunc() // calculate length without color coding, due to ANSI color characters padded to actual // string the final length is wrong than the original string length lineStr := fmt.Sprintf(" \"%s\" . ", message) lineLength := len(lineStr) // populate lines with color coding lineInColor := fmt.Sprintf(" \"%s\" . ", cyan(message)) maxContentWidth := lineLength terminal, err := ts.GetSize() if err != nil { // no coloring needed just send as is return message } var msg string switch { case len(lineStr) > terminal.Col(): msg = lineInColor default: // on windows terminal turn off unicode characters var top, bottom, sideBar string if runtime.GOOS == "windows" { top = yellow("*" + strings.Repeat("*", maxContentWidth) + "*") bottom = yellow("*" + strings.Repeat("*", maxContentWidth) + "*") sideBar = yellow("|") } else { // color the rectangular box, use unicode characters here top = yellow("┏" + strings.Repeat("━", maxContentWidth) + "┓") bottom = yellow("┗" + strings.Repeat("━", maxContentWidth) + "┛") sideBar = yellow("┃") } // construct the final message msg = top + "\n" + sideBar + lineInColor + sideBar + "\n" + bottom } return msg }
func awwShucks() string { size, err := ts.GetSize() if err != nil { return "Aww shucks." } else if size.Col() < 80 { return "Aww shucks." } else { return ` _____ _ _ /\ / ____| | | | / \__ ____ __ | (___ | |__ _ _ ___| | _____ / /\ \ \ /\ / /\ \ /\ / / \___ \| '_ \| | | |/ __| |/ / __| / ____ \ V V / \ V V / ____) | | | | |_| | (__| <\__ \_ /_/ \_\_/\_/ \_/\_/ |_____/|_| |_|\__,_|\___|_|\_\___(_) ` } }
func main() { probe.Init() // Set project's root source path. probe.SetAppInfo("Release-Tag", mcReleaseTag) app := registerApp() app.Before = registerBefore app.ExtraInfo = func() map[string]string { if _, e := ts.GetSize(); e != nil { globalQuietFlag = true } if globalDebugFlag { return getSystemData() } return make(map[string]string) } app.RunAndExitOnError() }
func main() { probe.Init() // Set project's root source path. probe.SetAppInfo("Release-Tag", mcReleaseTag) probe.SetAppInfo("Commit", mcShortCommitID) contentdb.Init() // Load contentdb into memory. app := registerApp() app.Before = registerBefore app.ExtraInfo = func() map[string]string { if _, e := ts.GetSize(); e != nil { globalQuiet = true } if globalDebug { return getSystemData() } return make(map[string]string) } app.RunAndExitOnError() }
// FormatJSONSyntaxError generates a pretty printed json syntax error since // golang doesn't provide an easy way to report the location of the error func FormatJSONSyntaxError(data io.Reader, sErr *json.SyntaxError) error { if sErr == nil { return nil } var readLine bytes.Buffer bio := bufio.NewReader(data) errLine := int64(1) readBytes := int64(0) // termWidth is set to a default one to use when we are // not able to calculate terminal width via OS syscalls termWidth := 25 // errorShift is the length of the minimum needed place for // error msg accessoires, like <--, etc.. We calculate it // dynamically to avoid an eventual bug after modifying errorFmt errorShift := len(fmt.Sprintf(errorFmt, 1, "")) if termSize, err := ts.GetSize(); err == nil { termWidth = termSize.Col() } for { b, err := bio.ReadByte() if err != nil { if err != io.EOF { return err } break } readBytes++ if readBytes > sErr.Offset { break } switch b { case '\n': readLine.Reset() errLine++ case '\t': readLine.WriteByte(' ') case '\r': break default: readLine.WriteByte(b) } } lineLen := readLine.Len() idx := lineLen - termWidth + errorShift if idx < 0 || idx > lineLen-1 { idx = 0 } errorStr := fmt.Sprintf("JSON syntax error at line %d, col %d : %s.\n", errLine, readLine.Len(), sErr) errorStr += fmt.Sprintf(errorFmt, errLine, readLine.String()[idx:]) return errors.New(errorStr) }
func terminalWidth() (int, error) { size, err := ts.GetSize() return size.Col(), err }