func (c *Application) writeHelp(width int, w io.Writer) { s := []string{formatArgsAndFlags(c.Name, c.argGroup, c.flagGroup)} if len(c.commands) > 0 { s = append(s, "<command>", "[<flags>]", "[<args> ...]") } prefix := "usage: " usage := strings.Join(s, " ") buf := bytes.NewBuffer(nil) doc.ToText(buf, usage, "", preIndent, width-len(prefix)) lines := strings.Split(strings.TrimRight(buf.String(), "\n"), "\n") fmt.Fprintf(w, "%s%s\n", prefix, lines[0]) for _, l := range lines[1:] { fmt.Fprintf(w, "%*s%s\n", len(prefix), "", l) } if c.Help != "" { fmt.Fprintf(w, "\n") doc.ToText(w, c.Help, "", preIndent, width) } c.flagGroup.writeHelp(width, w) c.argGroup.writeHelp(width, w) if len(c.commands) > 0 { fmt.Fprintf(w, "\nCommands:\n") c.helpCommands(width, w) } }
func godoc(member, content string) string { undocumented := "// " + exportable(member) + " is undocumented.\n" node, err := html.Parse(strings.NewReader(content)) if err != nil { return undocumented } _, v, err := sandblast.Extract(node) if err != nil { return undocumented } v = strings.TrimSpace(v) if v == "" { return undocumented } if member != "" { v = exportable(member) + " " + strings.ToLower(v[0:1]) + v[1:] } out := bytes.NewBuffer(nil) doc.ToText(out, v, "// ", "", 72) return out.String() }
func (p *docPrinter) printText(s string) { s = strings.TrimRight(s, " \t\n") if s != "" { p.scratch.Reset() godoc.ToText(&p.scratch, s, textIndent, textIndent+"\t", textWidth) blank := 0 for _, line := range bytes.Split(p.scratch.Bytes(), []byte{'\n'}) { if len(line) == 0 { blank++ } else { const k = len(textIndent) + 1 if blank == 2 && len(line) > k && line[k] != ' ' { p.WriteString("\n") p.PushHighlight(headerGroup) p.Write(line) p.PopHighlight() p.WriteString("\n") } else { for i := 0; i < blank; i++ { p.WriteString("\n") } p.Write(line) p.WriteString("\n") } blank = 0 } } p.WriteString("\n") } }
// packageDoc prints the docs for the package (package doc plus one-liners of the rest). func (pkg *Package) packageDoc(showRaml bool) { defer pkg.flush() if pkg.showInternals() && !showRaml { pkg.packageClause(false) } doc.ToText(&pkg.buf, pkg.doc.Doc, "", indent, indentedWidth) pkg.newlines(1) if !pkg.showInternals() { // Show only package docs for commands. return } pkg.newlines(1) if showRaml == true { pkg.ramls() } else { pkg.valueSummary(pkg.doc.Consts) pkg.valueSummary(pkg.doc.Vars) pkg.funcSummary(pkg.doc.Funcs) pkg.typeSummary() pkg.bugs() } }
// commentTextFn formats a source code comment as text. func commentTextFn(v string) string { const indent = " " var buf bytes.Buffer godoc.ToText(&buf, v, indent, "\t", 80-2*len(indent)) p := buf.Bytes() return string(p) }
func formatTwoColumns(w io.Writer, indent, padding, width int, rows [][2]string) { // Find size of first column. s := 0 for _, row := range rows { if c := len(row[0]); c > s && c < 30 { s = c } } indentStr := strings.Repeat(" ", indent) offsetStr := strings.Repeat(" ", s+padding) for _, row := range rows { buf := bytes.NewBuffer(nil) doc.ToText(buf, row[1], "", preIndent, width-s-padding-indent) lines := strings.Split(strings.TrimRight(buf.String(), "\n"), "\n") fmt.Fprintf(w, "%s%-*s%*s", indentStr, s, row[0], padding, "") if len(row[0]) >= 30 { fmt.Fprintf(w, "\n%s%s", indentStr, offsetStr) } fmt.Fprintf(w, "%s\n", lines[0]) for _, line := range lines[1:] { fmt.Fprintf(w, "%s%s%s\n", indentStr, offsetStr, line) } } }
// printMethodDoc prints the docs for matches of symbol.method. // If symbol is empty, it prints all methods that match the name. // It reports whether it found any methods. func (pkg *Package) printMethodDoc(symbol, method string) bool { defer pkg.flush() types := pkg.findTypes(symbol) if types == nil { if symbol == "" { return false } pkg.Fatalf("symbol %s is not a type in package %s installed in %q", symbol, pkg.name, pkg.build.ImportPath) } found := false for _, typ := range types { if len(typ.Methods) > 0 { for _, meth := range typ.Methods { if match(method, meth.Name) { decl := meth.Decl decl.Body = nil pkg.emit(meth.Doc, decl) found = true } } continue } // Type may be an interface. The go/doc package does not attach // an interface's methods to the doc.Type. We need to dig around. spec := pkg.findTypeSpec(typ.Decl, typ.Name) inter, ok := spec.Type.(*ast.InterfaceType) if !ok { // Not an interface type. // TODO? Maybe handle struct fields here. continue } for _, iMethod := range inter.Methods.List { // This is an interface, so there can be only one name. // TODO: Anonymous methods (embedding) if len(iMethod.Names) == 0 { continue } name := iMethod.Names[0].Name if match(method, name) { // pkg.oneLineField(iMethod, 0) if iMethod.Doc != nil { for _, comment := range iMethod.Doc.List { doc.ToText(&pkg.buf, comment.Text, "", indent, indentedWidth) } } s := pkg.oneLineNode(iMethod.Type) // Hack: s starts "func" but there is no name present. // We could instead build a FuncDecl but it's not worthwhile. lineComment := "" if iMethod.Comment != nil { lineComment = fmt.Sprintf(" %s", iMethod.Comment.List[0].Text) } pkg.Printf("func %s%s%s\n", name, s[4:], lineComment) found = true } } } return found }
func writeEnum(scope Scope, opt Option, delta int) { fmt.Println() if opt.Description != "" { doc.ToText(os.Stdout, opt.Description, " // ", "", 73) // fmt.Printf(" // %s\n", opt.Description) } fmt.Printf(" %s %s = %d\n", scope.Name+translateName(opt.Name), scope.Name, opt.Code+delta) }
func comment_textFunc(comment, indent, preIndent string) string { var buf bytes.Buffer doc.ToText(&buf, comment, indent, preIndent, punchCardWidth-2*len(indent)) if containsOnlySpace(buf.Bytes()) { return "" } return buf.String() }
func printParagraph(indent string, bulletCharacter byte, text string) { var buf bytes.Buffer doc.ToText(&buf, text, indent, indent, 79-len(indent)) output := buf.Bytes() if len(output) > len(indent) && len(indent) > 2 { bulletPos := len(indent) - 2 output[bulletPos] = bulletCharacter } os.Stdout.Write(output) }
func (p *docPrinter) printText(s string) { s = strings.TrimRight(s, " \t\n") if s != "" { doc.ToText(&p.buf, s, textIndent, textIndent+"\t", textWidth) b := p.buf.Bytes() if b[len(b)-1] != '\n' { p.buf.WriteByte('\n') } p.buf.WriteByte('\n') } }
func (d *Doc) String() string { buf := &bytes.Buffer{} if d.Import != "" { fmt.Fprintf(buf, "import \"%s\"\n\n", d.Import) } fmt.Fprintf(buf, "%s\n\n", d.Decl) if d.Doc == "" { d.Doc = "Undocumented." } doc.ToText(buf, d.Doc, indent, preIndent, *linelength) return buf.String() }
func (c *Application) helpCommands(width int, w io.Writer) { for _, cmd := range c.commandOrder { fmt.Fprintf(w, " %s\n", formatArgsAndFlags(cmd.name, cmd.argGroup, cmd.flagGroup)) buf := bytes.NewBuffer(nil) doc.ToText(buf, cmd.help, "", preIndent, width-4) lines := strings.Split(strings.TrimRight(buf.String(), "\n"), "\n") for _, line := range lines { fmt.Fprintf(w, " %s\n", line) } fmt.Fprintf(w, "\n") } }
// packageDoc prints the docs for the package (package doc plus one-liners of the rest). func (pkg *Package) packageDoc() { defer pkg.flush() pkg.packageClause(false) doc.ToText(&pkg.buf, pkg.doc.Doc, "", "\t", 80) pkg.newlines(2) pkg.valueSummary(pkg.doc.Consts) pkg.valueSummary(pkg.doc.Vars) pkg.funcSummary(pkg.doc.Funcs) pkg.typeSummary() pkg.bugs() }
// emit prints the node. func (pkg *Package) emit(comment string, node ast.Node) { if node != nil { err := format.Node(&pkg.buf, pkg.fs, node) if err != nil { log.Fatal(err) } if comment != "" { pkg.newlines(2) // Guarantee blank line before comment. doc.ToText(&pkg.buf, comment, " ", indent, indentedWidth) } pkg.newlines(1) } }
// emit prints the node. func (pkg *Package) emit(comment string, node ast.Node) { if node != nil { err := format.Node(&pkg.buf, pkg.fs, node) if err != nil { log.Fatal(err) } if comment != "" { pkg.newlines(1) doc.ToText(&pkg.buf, comment, " ", indent, indentedWidth) pkg.newlines(2) // Blank line after comment to separate from next item. } else { pkg.newlines(1) } } }
func (c *cmdGroup) writeHelp(width int, w io.Writer) { if len(c.commands) == 0 { return } fmt.Fprintf(w, "\nCommands:\n") flattened := c.flattenedCommands() for _, cmd := range flattened { fmt.Fprintf(w, " %s\n", formatArgsAndFlags(cmd.FullCommand(), cmd.argGroup, cmd.flagGroup, cmd.cmdGroup)) buf := bytes.NewBuffer(nil) doc.ToText(buf, cmd.help, "", preIndent, width-4) lines := strings.Split(strings.TrimRight(buf.String(), "\n"), "\n") for _, line := range lines { fmt.Fprintf(w, " %s\n", line) } fmt.Fprintf(w, "\n") } }
// writeSampleDescription writes the given attribute to w // prefixed by the given indentation string. func writeSampleDescription(w io.Writer, f Attr, indent string) { previousText := false // section marks the start of a new section of the comment; // sections are separated with empty lines. section := func() { if previousText { fmt.Fprintf(w, "%s\n", strings.TrimRightFunc(indent, unicode.IsSpace)) } previousText = true } descr := strings.TrimSpace(f.Description) if descr != "" { section() doc.ToText(w, descr, indent, " ", textWidth-len(indent)) } vars := make([]string, 0, len(f.EnvVars)+1) if f.EnvVar != "" { vars = append(vars, "$"+f.EnvVar) } for _, v := range f.EnvVars { vars = append(vars, "$"+v) } if len(vars) > 0 { section() fmt.Fprintf(w, "%sDefault value taken from %s.\n", indent, wordyList(vars)) } attrText := "" switch { case f.Secret && f.Immutable: attrText = "immutable and considered secret" case f.Secret: attrText = "considered secret" case f.Immutable: attrText = "immutable" } if attrText != "" { section() fmt.Fprintf(w, "%sThis attribute is %s.\n", indent, attrText) } section() }
func godoc(name, helpText string, indent string) string { node, err := html.Parse(strings.NewReader(helpText)) if err != nil { return "no documentation" } _, helpText, err = sandblast.Extract(node) if err != nil { return "no documentation" } helpText = strings.TrimSpace(helpText) if helpText == "" { helpText = "no documentation" } text := upper(name) + " - " + helpText out := bytes.NewBuffer(nil) doc.ToText(out, text, indent+"// ", "", 100) return out.String() }
// packageDoc prints the docs for the package (package doc plus one-liners of the rest). func (pkg *Package) packageDoc() { defer pkg.flush() if pkg.showInternals() { pkg.packageClause(false) } doc.ToText(&pkg.buf, pkg.doc.Doc, "", indent, indentedWidth) pkg.newlines(1) if !pkg.showInternals() { // Show only package docs for commands. return } pkg.newlines(2) // Guarantee blank line before the components. pkg.valueSummary(pkg.doc.Consts) pkg.valueSummary(pkg.doc.Vars) pkg.funcSummary(pkg.doc.Funcs) pkg.typeSummary() pkg.bugs() }
// packageDoc prints the docs for the package (package doc plus one-liners of the rest). func (pkg *Package) packageDoc() { defer pkg.flush() if pkg.showInternals() { pkg.packageClause(false) } doc.ToText(&pkg.buf, pkg.doc.Doc, "", "\t", 80) pkg.newlines(1) if !pkg.showInternals() { // Show only package docs for commands. return } pkg.newlines(1) pkg.valueSummary(pkg.doc.Consts) pkg.valueSummary(pkg.doc.Vars) pkg.funcSummary(pkg.doc.Funcs) pkg.typeSummary() pkg.bugs() }
// UsageForContextWithTemplate is the base usage function. You generally don't need to use this. func (a *Application) UsageForContextWithTemplate(context *ParseContext, indent int, tmpl string) error { width := guessWidth(a.writer) funcs := template.FuncMap{ "Indent": func(level int) string { return strings.Repeat(" ", level*indent) }, "Wrap": func(indent int, s string) string { buf := bytes.NewBuffer(nil) indentText := strings.Repeat(" ", indent) doc.ToText(buf, s, indentText, indentText, width-indent) return buf.String() }, "FormatFlag": formatFlag, "FlagsToTwoColumns": func(f []*FlagModel) [][2]string { rows := [][2]string{} haveShort := false for _, flag := range f { if flag.Short != 0 { haveShort = true break } } for _, flag := range f { if !flag.Hidden { rows = append(rows, [2]string{formatFlag(haveShort, flag), flag.Help}) } } return rows }, "RequiredFlags": func(f []*FlagModel) []*FlagModel { requiredFlags := []*FlagModel{} for _, flag := range f { if flag.Required == true { requiredFlags = append(requiredFlags, flag) } } return requiredFlags }, "OptionalFlags": func(f []*FlagModel) []*FlagModel { optionalFlags := []*FlagModel{} for _, flag := range f { if flag.Required == false { optionalFlags = append(optionalFlags, flag) } } return optionalFlags }, "ArgsToTwoColumns": func(a []*ArgModel) [][2]string { rows := [][2]string{} for _, arg := range a { s := "<" + arg.Name + ">" if !arg.Required { s = "[" + s + "]" } rows = append(rows, [2]string{s, arg.Help}) } return rows }, "FormatTwoColumns": func(rows [][2]string) string { buf := bytes.NewBuffer(nil) formatTwoColumns(buf, indent, indent, width, rows) return buf.String() }, "FormatTwoColumnsWithIndent": func(rows [][2]string, indent, padding int) string { buf := bytes.NewBuffer(nil) formatTwoColumns(buf, indent, padding, width, rows) return buf.String() }, "FormatAppUsage": formatAppUsage, "FormatCommandUsage": formatCmdUsage, "IsCumulative": func(value Value) bool { r, ok := value.(remainderArg) return ok && r.IsCumulative() }, "Char": func(c rune) string { return string(c) }, } t, err := template.New("usage").Funcs(funcs).Parse(tmpl) if err != nil { return err } var selectedCommand *CmdModel if context.SelectedCommand != nil { selectedCommand = context.SelectedCommand.Model() } ctx := templateContext{ App: a.Model(), Width: width, Context: &templateParseContext{ SelectedCommand: selectedCommand, FlagGroupModel: context.flags.Model(), ArgGroupModel: context.arguments.Model(), }, } return t.Execute(a.writer, ctx) }
func comment_textFunc(comment, indent, preIndent string) string { var buf bytes.Buffer doc.ToText(&buf, comment, indent, preIndent, punchCardWidth-2*len(indent)) return buf.String() }
func _formatIndent(target, indent, preIndent string) string { var buffer bytes.Buffer doc.ToText(&buffer, target, indent, preIndent, punchCardWidth-2*len(indent)) return buffer.String() }
// WordWrap wraps paragraphs of text to width. func WordWrap(s string, width int) string { buf := new(bytes.Buffer) doc.ToText(buf, s, "", "", width) return buf.String() }
func wrap(indent string, s string) string { var buf bytes.Buffer doc.ToText(&buf, s, indent, indent+" ", 80-len(indent)) return buf.String() }
// Wrap wraps the string s to the maximum line length given. Each line // will be prefaced with leading. func Wrap(s, leading string, max int) string { buf := &bytes.Buffer{} doc.ToText(buf, s, leading, "", max) return string(buf.Bytes()) }