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, &params); 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  }