github.com/getgauge/gauge@v1.6.9/api/lang/symbols.go (about) 1 /*---------------------------------------------------------------- 2 * Copyright (c) ThoughtWorks, Inc. 3 * Licensed under the Apache License, Version 2.0 4 * See LICENSE in the project root for license information. 5 *----------------------------------------------------------------*/ 6 7 package lang 8 9 import ( 10 "encoding/json" 11 "fmt" 12 "sort" 13 "strings" 14 15 "github.com/getgauge/gauge/gauge" 16 "github.com/getgauge/gauge/parser" 17 "github.com/getgauge/gauge/util" 18 "github.com/sourcegraph/go-langserver/pkg/lsp" 19 "github.com/sourcegraph/jsonrpc2" 20 ) 21 22 func documentSymbols(req *jsonrpc2.Request) (interface{}, error) { 23 var params lsp.DocumentSymbolParams 24 var err error 25 if err = json.Unmarshal(*req.Params, ¶ms); err != nil { 26 return nil, fmt.Errorf("failed to parse request %v", err) 27 } 28 file := util.ConvertURItoFilePath(params.TextDocument.URI) 29 content := getContent(params.TextDocument.URI) 30 if util.IsConcept(file) { 31 return getConceptSymbols(content, file), nil 32 } 33 spec, parseResult, err := new(parser.SpecParser).Parse(content, gauge.NewConceptDictionary(), file) 34 if err != nil { 35 return nil, err 36 } 37 if !parseResult.Ok { 38 return nil, fmt.Errorf("parsing failed for %s. %s", file, parseResult.Errors()) 39 } 40 var symbols = make([]*lsp.SymbolInformation, 0) 41 symbols = append(symbols, getSpecSymbol(spec)) 42 for _, scn := range spec.Scenarios { 43 symbols = append(symbols, getScenarioSymbol(scn, file)) 44 } 45 return symbols, nil 46 } 47 48 func workspaceSymbols(req *jsonrpc2.Request) (interface{}, error) { 49 var params lsp.WorkspaceSymbolParams 50 var err error 51 if err = json.Unmarshal(*req.Params, ¶ms); err != nil { 52 return nil, fmt.Errorf("failed to parse request %v", err) 53 } 54 55 if len(params.Query) < 2 { 56 return nil, nil 57 } 58 59 var specSymbols = make([]*lsp.SymbolInformation, 0) 60 var scnSymbols = make([]*lsp.SymbolInformation, 0) 61 specDetails := provider.GetAvailableSpecDetails([]string{}) 62 for _, specDetail := range specDetails { 63 if !specDetail.HasSpec() { 64 continue 65 } 66 spec := specDetail.Spec 67 if strings.Contains(strings.ToLower(specDetail.Spec.Heading.Value), strings.ToLower(params.Query)) { 68 specSymbols = append(specSymbols, getSpecSymbol(spec)) 69 } 70 for _, scn := range spec.Scenarios { 71 if strings.Contains(strings.ToLower(scn.Heading.Value), strings.ToLower(params.Query)) { 72 scnSymbols = append(scnSymbols, getScenarioSymbol(scn, spec.FileName)) 73 } 74 } 75 } 76 sort.Sort(byName(specSymbols)) 77 sort.Sort(byName(scnSymbols)) 78 return append(specSymbols, scnSymbols...), nil 79 } 80 81 func getSpecSymbol(s *gauge.Specification) *lsp.SymbolInformation { 82 return &lsp.SymbolInformation{ 83 Name: fmt.Sprintf("# %s", s.Heading.Value), 84 Kind: lsp.SKNamespace, 85 Location: lsp.Location{ 86 URI: util.ConvertPathToURI(s.FileName), 87 Range: lsp.Range{ 88 Start: lsp.Position{Line: s.Heading.LineNo - 1, Character: 0}, 89 End: lsp.Position{Line: s.Heading.LineNo - 1, Character: len(s.Heading.Value)}, 90 }, 91 }, 92 } 93 } 94 95 func getScenarioSymbol(s *gauge.Scenario, path string) *lsp.SymbolInformation { 96 return &lsp.SymbolInformation{ 97 Name: fmt.Sprintf("## %s", s.Heading.Value), 98 Kind: lsp.SKNamespace, 99 Location: lsp.Location{ 100 URI: util.ConvertPathToURI(path), 101 Range: lsp.Range{ 102 Start: lsp.Position{Line: s.Heading.LineNo - 1, Character: 0}, 103 End: lsp.Position{Line: s.Heading.LineNo - 1, Character: len(s.Heading.Value)}, 104 }, 105 }, 106 } 107 } 108 109 func getConceptSymbols(content, file string) []*lsp.SymbolInformation { 110 concepts, _ := new(parser.ConceptParser).Parse(content, file) 111 var symbols = make([]*lsp.SymbolInformation, 0) 112 for _, cpt := range concepts { 113 symbols = append(symbols, &lsp.SymbolInformation{ 114 Name: fmt.Sprintf("# %s", cpt.LineText), 115 Kind: lsp.SKNamespace, 116 Location: lsp.Location{ 117 URI: util.ConvertPathToURI(file), 118 Range: lsp.Range{ 119 Start: lsp.Position{Line: cpt.LineNo - 1, Character: 0}, 120 End: lsp.Position{Line: cpt.LineNo - 1, Character: len(cpt.LineText)}, 121 }, 122 }, 123 }) 124 } 125 return symbols 126 } 127 128 type byName []*lsp.SymbolInformation 129 130 func (s byName) Len() int { 131 return len(s) 132 } 133 134 func (s byName) Swap(i, j int) { 135 s[i], s[j] = s[j], s[i] 136 } 137 138 func (s byName) Less(i, j int) bool { 139 return strings.Compare(s[i].Name, s[j].Name) < 0 140 }