kythe.io@v0.0.68-0.20240422202219-7225dbc01741/kythe/go/services/cli/command_docs.go (about) 1 /* 2 * Copyright 2017 The Kythe Authors. All rights reserved. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package cli 18 19 import ( 20 "context" 21 "flag" 22 "fmt" 23 "strings" 24 25 "kythe.io/kythe/go/util/log" 26 "kythe.io/kythe/go/util/markedsource" 27 28 xpb "kythe.io/kythe/proto/xref_go_proto" 29 ) 30 31 type docsCommand struct { 32 baseKytheCommand 33 nodeFilters string 34 includeChildren bool 35 renderMarkedSource bool 36 } 37 38 func (docsCommand) Name() string { return "docs" } 39 func (docsCommand) Synopsis() string { return "display documentation for a node" } 40 func (c *docsCommand) SetFlags(flag *flag.FlagSet) { 41 flag.StringVar(&c.nodeFilters, "filters", "", "Comma-separated list of node fact filters (default returns all)") 42 flag.BoolVar(&c.includeChildren, "include_children", false, "Include documentation for children of the given node") 43 flag.BoolVar(&c.renderMarkedSource, "render_marked_source", false, "Render each node's MarkedSource") 44 } 45 func (c docsCommand) Run(ctx context.Context, flag *flag.FlagSet, api API) error { 46 req := &xpb.DocumentationRequest{ 47 Ticket: flag.Args(), 48 IncludeChildren: c.includeChildren, 49 } 50 if c.nodeFilters != "" { 51 req.Filter = strings.Split(c.nodeFilters, ",") 52 } 53 LogRequest(req) 54 reply, err := api.XRefService.Documentation(ctx, req) 55 if err != nil { 56 return err 57 } 58 return c.displayDocumentation(reply) 59 } 60 61 func findLinkText(rawText string) []string { 62 var linkText []string 63 var current []int 64 var invalid bool 65 for i := 0; i < len(rawText); i++ { 66 c := rawText[i] 67 switch c { 68 case '[': 69 current = append(current, len(linkText)) 70 linkText = append(linkText, "") 71 case ']': 72 if len(current) == 0 { 73 invalid = true 74 continue 75 } 76 current = current[:len(current)-1] 77 default: 78 if c == '\\' { 79 if i+1 >= len(rawText) { 80 invalid = true 81 continue 82 } 83 i++ 84 c = rawText[i] 85 } 86 for _, l := range current { 87 linkText[l] += string(c) 88 } 89 } 90 } 91 if invalid { 92 log.Warningf("invalid document raw text: %q", rawText) 93 } 94 return linkText 95 } 96 97 func (c docsCommand) displayDoc(indent string, doc *xpb.DocumentationReply_Document) { 98 fmt.Println(indent + showSignature(doc.MarkedSource)) 99 if len(doc.Text.GetRawText()) > 0 { 100 fmt.Println(indent + doc.Text.RawText) 101 linkText := findLinkText(doc.Text.RawText) 102 for i, link := range doc.Text.Link { 103 if i >= len(linkText) { 104 log.Warningf("mismatch between raw text and number of links: %v", doc) 105 break 106 } 107 if len(link.Definition) > 0 { 108 fmt.Printf("%s %s: %s\n", indent, linkText[i], strings.Join(link.Definition, "\t")) 109 } 110 } 111 if c.renderMarkedSource { 112 contentType := markedsource.PlaintextContent 113 fmt.Printf("%s Identifier: %q\n", indent, 114 markedsource.RenderSimpleIdentifier(doc.MarkedSource, contentType, nil)) 115 fmt.Printf("%s Qualified Name: %q\n", indent, 116 markedsource.RenderSimpleQualifiedName(doc.MarkedSource, true, contentType, nil)) 117 fmt.Printf("%s Callsite Signature: %q\n", indent, 118 markedsource.RenderCallSiteSignature(doc.MarkedSource)) 119 fmt.Printf("%s Signature: %q\n", indent, 120 markedsource.RenderSignature(doc.MarkedSource, contentType, nil)) 121 } 122 } 123 124 for _, child := range doc.Children { 125 fmt.Println() 126 c.displayDoc(indent+" ", child) 127 } 128 } 129 130 func (c docsCommand) displayDocumentation(reply *xpb.DocumentationReply) error { 131 if DisplayJSON { 132 return PrintJSONMessage(reply) 133 } else if len(reply.Document) == 0 { 134 return nil 135 } 136 137 c.displayDoc("", reply.Document[0]) 138 for _, doc := range reply.Document[1:] { 139 fmt.Println() 140 c.displayDoc("", doc) 141 } 142 return nil 143 }