github.com/getgauge/gauge@v1.6.9/api/lang/definition.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 12 "github.com/getgauge/gauge/util" 13 14 "fmt" 15 16 "github.com/getgauge/common" 17 "github.com/getgauge/gauge-proto/go/gauge_messages" 18 "github.com/getgauge/gauge/gauge" 19 "github.com/getgauge/gauge/parser" 20 "github.com/sourcegraph/go-langserver/pkg/lsp" 21 "github.com/sourcegraph/jsonrpc2" 22 ) 23 24 func definition(req *jsonrpc2.Request) (interface{}, error) { 25 var params lsp.TextDocumentPositionParams 26 if err := json.Unmarshal(*req.Params, ¶ms); err != nil { 27 return nil, err 28 } 29 30 fileContent := getContent(params.TextDocument.URI) 31 if util.IsConcept(util.ConvertURItoFilePath(params.TextDocument.URI)) { 32 concepts, _ := new(parser.ConceptParser).Parse(fileContent, "") 33 for _, concept := range concepts { 34 for _, step := range concept.ConceptSteps { 35 if (step.LineNo - 1) == params.Position.Line { 36 return search(req, step) 37 } 38 } 39 } 40 } else { 41 spec, _ := new(parser.SpecParser).ParseSpecText(fileContent, "") 42 for _, item := range spec.AllItems() { 43 if item.Kind() == gauge.StepKind { 44 step := item.(*gauge.Step) 45 if (step.LineNo - 1) == params.Position.Line { 46 return search(req, step) 47 } 48 } 49 } 50 } 51 return nil, nil 52 } 53 54 func search(req *jsonrpc2.Request, step *gauge.Step) (interface{}, error) { 55 if loc, _ := searchConcept(step); loc != nil { 56 return loc, nil 57 } 58 return searchStep(req, step) 59 60 } 61 62 func searchStep(req *jsonrpc2.Request, step *gauge.Step) (interface{}, error) { 63 if lRunner.runner == nil { 64 return nil, nil 65 } 66 responseMessage, err := getStepNameResponse(step.Value) 67 if err != nil { 68 return nil, err 69 } 70 if responseMessage == nil || !(responseMessage.GetIsStepPresent()) { 71 return nil, fmt.Errorf("Step implementation not found for step : %s", step.Value) 72 } 73 74 if responseMessage.IsExternal { 75 return nil, fmt.Errorf("implementation source not found: Step implementation referred from an external project or library") 76 } 77 78 return getLspLocationForStep(responseMessage.GetFileName(), responseMessage.GetSpan()), nil 79 } 80 81 func searchConcept(step *gauge.Step) (interface{}, error) { 82 if concept := provider.SearchConceptDictionary(step.Value); concept != nil { 83 return getLspLocationForConcept(concept.FileName, concept.ConceptStep.LineNo) 84 } 85 return nil, nil 86 } 87 88 func getLspLocationForStep(fileName string, span *gauge_messages.Span) lsp.Location { 89 return lsp.Location{ 90 URI: util.ConvertPathToURI(fileName), 91 Range: lsp.Range{ 92 Start: lsp.Position{Line: int(span.Start - 1), Character: int(span.StartChar)}, 93 End: lsp.Position{Line: int(span.End - 1), Character: int(span.EndChar)}, 94 }, 95 } 96 } 97 98 func getLspLocationForConcept(fileName string, lineNumber int) (interface{}, error) { 99 uri := util.ConvertPathToURI(fileName) 100 var endPos int 101 lineNo := lineNumber - 1 102 if isOpen(uri) { 103 endPos = len(getLine(uri, lineNo)) 104 } else { 105 contents, err := common.ReadFileContents(fileName) 106 if err != nil { 107 return nil, err 108 } 109 lines := util.GetLinesFromText(contents) 110 if len(lines) < lineNo { 111 return nil, fmt.Errorf("unable to read line %d from disk", lineNo+1) 112 } 113 endPos = len(lines[lineNo]) 114 } 115 return lsp.Location{ 116 URI: util.ConvertPathToURI(fileName), 117 Range: lsp.Range{ 118 Start: lsp.Position{Line: lineNo, Character: 0}, 119 End: lsp.Position{Line: lineNo, Character: endPos}, 120 }, 121 }, nil 122 }