github.com/nevalang/neva@v0.23.1-0.20240507185603-7696a9bb8dda/cmd/lsp/server/get_file_view.go (about)

     1  package server
     2  
     3  import (
     4  	"errors"
     5  	"strings"
     6  
     7  	src "github.com/nevalang/neva/internal/compiler/sourcecode"
     8  	"github.com/tliron/glsp"
     9  )
    10  
    11  type GetFileViewRequest struct {
    12  	WorkspaceURI URI `json:"workspaceUri"`
    13  	Document     struct {
    14  		URI      URI    `json:"uri"`
    15  		FileName string `json:"fileName"`
    16  	} `json:"document"`
    17  }
    18  
    19  type URI struct {
    20  	Path   string `json:"path"`
    21  	FSPath string `json:"fsPath"`
    22  }
    23  
    24  type GetFileViewResponce struct {
    25  	File  src.File `json:"file"`
    26  	Extra Extra    `json:"extra"` // info that is not presented in the file but needed for rendering
    27  }
    28  
    29  type Extra struct {
    30  	NodesPorts map[string]map[string]src.Interface `json:"nodesPorts"` // components -> nodes -> interface
    31  }
    32  
    33  func (s *Server) GetFileView(glspCtx *glsp.Context, req GetFileViewRequest) (GetFileViewResponce, error) {
    34  	if s.index == nil {
    35  		return GetFileViewResponce{}, nil
    36  	}
    37  
    38  	relFilePath := strings.TrimPrefix(req.Document.FileName, req.WorkspaceURI.Path)
    39  	relFilePath = strings.TrimPrefix(relFilePath, "/")
    40  
    41  	relPathParts := strings.Split(relFilePath, "/")           // relative path to file in slice
    42  	relPathLastPart := relPathParts[len(relPathParts)-1]      // file name with extension
    43  	relPartsWithoutFile := relPathParts[:len(relPathParts)-1] // relative path to package
    44  
    45  	pkgName := strings.Join(relPartsWithoutFile, "/")
    46  	fileName := strings.TrimSuffix(relPathLastPart, ".neva")
    47  
    48  	scope := src.Scope{
    49  		Location: src.Location{
    50  			ModRef:   s.index.EntryModRef,
    51  			PkgName:  pkgName,
    52  			FileName: fileName,
    53  		},
    54  		Build: *s.index,
    55  	}
    56  
    57  	pkg, ok := s.index.Modules[s.index.EntryModRef].Packages[pkgName]
    58  	if !ok {
    59  		return GetFileViewResponce{}, errors.New("no such package: " + pkgName)
    60  	}
    61  
    62  	file, ok := pkg[fileName]
    63  	if !ok {
    64  		return GetFileViewResponce{}, errors.New("no such file: " + fileName + "." + pkgName)
    65  	}
    66  
    67  	extra, err := getExtraForFile(file, scope)
    68  	if err != nil {
    69  		return GetFileViewResponce{}, err
    70  	}
    71  
    72  	return GetFileViewResponce{
    73  		File: file,
    74  		Extra: Extra{
    75  			NodesPorts: extra,
    76  		},
    77  	}, nil
    78  }
    79  
    80  func getExtraForFile(file src.File, scope src.Scope) (map[string]map[string]src.Interface, error) {
    81  	extra := map[string]map[string]src.Interface{}
    82  	for entityName, entity := range file.Entities {
    83  		if entity.Kind != src.ComponentEntity {
    84  			continue
    85  		}
    86  
    87  		nodesIfaces := map[string]src.Interface{}
    88  		for nodeName, node := range entity.Component.Nodes {
    89  			nodeEntity, _, err := scope.Entity(node.EntityRef)
    90  			if err != nil {
    91  				return nil, err
    92  			}
    93  
    94  			var iface src.Interface
    95  			if nodeEntity.Kind == src.ComponentEntity {
    96  				iface = nodeEntity.Component.Interface
    97  			} else if nodeEntity.Kind == src.InterfaceEntity {
    98  				iface = nodeEntity.Interface
    99  			}
   100  
   101  			nodesIfaces[nodeName] = iface
   102  		}
   103  
   104  		extra[entityName] = nodesIfaces
   105  	}
   106  
   107  	return extra, nil
   108  }