github.com/getgauge/gauge@v1.6.9/api/lang/codeLens.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 "fmt" 11 12 "encoding/json" 13 "strconv" 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 const ( 23 executeCommand = "gauge.execute" 24 debugCommand = "gauge.debug" 25 inParallelCommand = "gauge.execute.inParallel" 26 referencesCommand = "gauge.showReferences" 27 28 runSpecCodeLens = "Run Spec" 29 debugSpecCodeLens = "Debug Spec" 30 runInParallelCodeLens = "Run in parallel" 31 runScenarioCodeLens = "Run Scenario" 32 debugScenarioCodeLens = "Debug Scenario" 33 referenceCodeLens = "%s reference(s)" 34 ) 35 36 func codeLenses(req *jsonrpc2.Request) (interface{}, error) { 37 var params lsp.CodeLensParams 38 if err := json.Unmarshal(*req.Params, ¶ms); err != nil { 39 return nil, fmt.Errorf("failed to parse request %v", err) 40 } 41 if util.IsSpec(string(params.TextDocument.URI)) { 42 return getExecutionCodeLenses(params) 43 } 44 if util.IsConcept(string(params.TextDocument.URI)) { 45 return getConceptReferenceCodeLenses(params) 46 } 47 return getImplementationReferenceCodeLenses(params) 48 } 49 50 func getExecutionCodeLenses(params lsp.CodeLensParams) (interface{}, error) { 51 uri := params.TextDocument.URI 52 file := util.ConvertURItoFilePath(uri) 53 spec, res, err := new(parser.SpecParser).Parse(getContent(uri), gauge.NewConceptDictionary(), file) 54 if err != nil { 55 return nil, err 56 } 57 if !res.Ok { 58 return nil, concatenateErrors(res, file) 59 } 60 var codeLenses []lsp.CodeLens 61 runCodeLens := createCodeLens(spec.Heading.LineNo-1, runSpecCodeLens, executeCommand, getExecutionArgs(spec.FileName)) 62 codeLenses = append(codeLenses, runCodeLens) 63 if lRunner.lspID != "" { 64 debugCodeLens := createCodeLens(spec.Heading.LineNo-1, debugSpecCodeLens, debugCommand, getExecutionArgs(spec.FileName)) 65 codeLenses = append(codeLenses, debugCodeLens) 66 } 67 if spec.DataTable.IsInitialized() { 68 codeLenses = append(codeLenses, getDataTableLenses(spec)...) 69 } 70 return append(getScenarioCodeLenses(spec), codeLenses...), nil 71 } 72 73 func getConceptReferenceCodeLenses(params lsp.CodeLensParams) (interface{}, error) { 74 uri := params.TextDocument.URI 75 file := util.ConvertURItoFilePath(uri) 76 concepts, _ := new(parser.ConceptParser).Parse(getContent(uri), file) 77 allSteps := provider.AllSteps(false) 78 var lenses []lsp.CodeLens 79 for _, concept := range concepts { 80 lenses = append(lenses, createReferenceCodeLens(allSteps, uri, concept.Value, int(concept.LineNo))) 81 } 82 return lenses, nil 83 } 84 85 func getImplementationReferenceCodeLenses(params lsp.CodeLensParams) (interface{}, error) { 86 if lRunner.runner == nil { 87 return nil, nil 88 } 89 uri := params.TextDocument.URI 90 stepPositionsResponse, err := getStepPositionResponse(uri) 91 if err != nil { 92 return nil, err 93 } 94 allSteps := provider.AllSteps(true) 95 var lenses []lsp.CodeLens 96 for _, stepPosition := range stepPositionsResponse.GetStepPositions() { 97 lenses = append(lenses, createReferenceCodeLens(allSteps, uri, stepPosition.GetStepValue(), int(stepPosition.GetSpan().GetStart()))) 98 } 99 return lenses, nil 100 } 101 102 func createReferenceCodeLens(allSteps []*gauge.Step, uri lsp.DocumentURI, stepValue string, startPosition int) lsp.CodeLens { 103 var count int 104 for _, step := range allSteps { 105 if stepValue == step.Value { 106 count++ 107 } 108 } 109 lensTitle := fmt.Sprintf(referenceCodeLens, strconv.Itoa(count)) 110 lensPosition := lsp.Position{Line: startPosition - 1, Character: 0} 111 lineNo := startPosition - 1 112 args := []interface{}{uri, lensPosition, stepValue} 113 114 return createCodeLens(lineNo, lensTitle, referencesCommand, args) 115 } 116 117 func getDataTableLenses(spec *gauge.Specification) []lsp.CodeLens { 118 var lenses []lsp.CodeLens 119 lenses = append(lenses, createCodeLens(spec.Heading.LineNo-1, runInParallelCodeLens, inParallelCommand, getExecutionArgs(spec.FileName))) 120 return lenses 121 } 122 123 func getScenarioCodeLenses(spec *gauge.Specification) []lsp.CodeLens { 124 var lenses []lsp.CodeLens 125 for _, sce := range spec.Scenarios { 126 args := getExecutionArgs(fmt.Sprintf("%s:%d", spec.FileName, sce.Heading.LineNo)) 127 lens := createCodeLens(sce.Heading.LineNo-1, runScenarioCodeLens, executeCommand, args) 128 lenses = append(lenses, lens) 129 if lRunner.lspID != "" { 130 debugCodeLens := createCodeLens(sce.Heading.LineNo-1, debugScenarioCodeLens, debugCommand, args) 131 lenses = append(lenses, debugCodeLens) 132 } 133 } 134 return lenses 135 } 136 137 func createCodeLens(lineNo int, lensTitle, command string, args []interface{}) lsp.CodeLens { 138 return lsp.CodeLens{ 139 Range: lsp.Range{ 140 Start: lsp.Position{Line: lineNo, Character: 0}, 141 End: lsp.Position{Line: lineNo, Character: len(lensTitle)}, 142 }, 143 Command: lsp.Command{ 144 Command: command, 145 Title: lensTitle, 146 Arguments: args, 147 }, 148 } 149 } 150 151 func getExecutionArgs(id string) []interface{} { 152 var args []interface{} 153 return append(args, id) 154 } 155 156 func concatenateErrors(res *parser.ParseResult, file string) error { 157 errs := "" 158 for _, e := range res.ParseErrors { 159 errs = fmt.Sprintf("%s%s:%d %s\n", errs, e.FileName, e.LineNo, e.Message) 160 } 161 return fmt.Errorf("failed to parse %s\n%s", file, errs) 162 }