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  }