Improved performances and hover
This commit is contained in:
@@ -13,6 +13,7 @@ type ProjectTree struct {
|
|||||||
References []Reference
|
References []Reference
|
||||||
IsolatedFiles map[string]*ProjectNode
|
IsolatedFiles map[string]*ProjectNode
|
||||||
GlobalPragmas map[string][]string
|
GlobalPragmas map[string][]string
|
||||||
|
NodeMap map[string][]*ProjectNode
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pt *ProjectTree) ScanDirectory(rootPath string) error {
|
func (pt *ProjectTree) ScanDirectory(rootPath string) error {
|
||||||
@@ -385,7 +386,19 @@ func (pt *ProjectTree) indexValue(file string, val parser.Value) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (pt *ProjectTree) RebuildIndex() {
|
||||||
|
pt.NodeMap = make(map[string][]*ProjectNode)
|
||||||
|
visitor := func(n *ProjectNode) {
|
||||||
|
pt.NodeMap[n.Name] = append(pt.NodeMap[n.Name], n)
|
||||||
|
if n.RealName != n.Name {
|
||||||
|
pt.NodeMap[n.RealName] = append(pt.NodeMap[n.RealName], n)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pt.Walk(visitor)
|
||||||
|
}
|
||||||
|
|
||||||
func (pt *ProjectTree) ResolveReferences() {
|
func (pt *ProjectTree) ResolveReferences() {
|
||||||
|
pt.RebuildIndex()
|
||||||
for i := range pt.References {
|
for i := range pt.References {
|
||||||
ref := &pt.References[i]
|
ref := &pt.References[i]
|
||||||
if isoNode, ok := pt.IsolatedFiles[ref.File]; ok {
|
if isoNode, ok := pt.IsolatedFiles[ref.File]; ok {
|
||||||
@@ -397,14 +410,21 @@ func (pt *ProjectTree) ResolveReferences() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (pt *ProjectTree) FindNode(root *ProjectNode, name string, predicate func(*ProjectNode) bool) *ProjectNode {
|
func (pt *ProjectTree) FindNode(root *ProjectNode, name string, predicate func(*ProjectNode) bool) *ProjectNode {
|
||||||
|
if pt.NodeMap == nil {
|
||||||
|
pt.RebuildIndex()
|
||||||
|
}
|
||||||
|
|
||||||
if strings.Contains(name, ".") {
|
if strings.Contains(name, ".") {
|
||||||
parts := strings.Split(name, ".")
|
parts := strings.Split(name, ".")
|
||||||
rootName := parts[0]
|
rootName := parts[0]
|
||||||
|
|
||||||
var candidates []*ProjectNode
|
candidates := pt.NodeMap[rootName]
|
||||||
pt.findAllNodes(root, rootName, &candidates)
|
|
||||||
|
|
||||||
for _, cand := range candidates {
|
for _, cand := range candidates {
|
||||||
|
if !pt.isDescendant(cand, root) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
curr := cand
|
curr := cand
|
||||||
valid := true
|
valid := true
|
||||||
for i := 1; i < len(parts); i++ {
|
for i := 1; i < len(parts); i++ {
|
||||||
@@ -426,26 +446,33 @@ func (pt *ProjectTree) FindNode(root *ProjectNode, name string, predicate func(*
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if root.RealName == name || root.Name == name {
|
candidates := pt.NodeMap[name]
|
||||||
if predicate == nil || predicate(root) {
|
for _, cand := range candidates {
|
||||||
return root
|
if !pt.isDescendant(cand, root) {
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
}
|
if predicate == nil || predicate(cand) {
|
||||||
for _, child := range root.Children {
|
return cand
|
||||||
if res := pt.FindNode(child, name, predicate); res != nil {
|
|
||||||
return res
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pt *ProjectTree) findAllNodes(root *ProjectNode, name string, results *[]*ProjectNode) {
|
func (pt *ProjectTree) isDescendant(node, root *ProjectNode) bool {
|
||||||
if root.RealName == name || root.Name == name {
|
if node == root {
|
||||||
*results = append(*results, root)
|
return true
|
||||||
}
|
}
|
||||||
for _, child := range root.Children {
|
if root == nil {
|
||||||
pt.findAllNodes(child, name, results)
|
return true
|
||||||
}
|
}
|
||||||
|
curr := node
|
||||||
|
for curr != nil {
|
||||||
|
if curr == root {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
curr = curr.Parent
|
||||||
|
}
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
type QueryResult struct {
|
type QueryResult struct {
|
||||||
|
|||||||
@@ -92,7 +92,9 @@ type VersionedTextDocumentIdentifier struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type TextDocumentContentChangeEvent struct {
|
type TextDocumentContentChangeEvent struct {
|
||||||
Text string `json:"text"`
|
Range *Range `json:"range,omitempty"`
|
||||||
|
RangeLength int `json:"rangeLength,omitempty"`
|
||||||
|
Text string `json:"text"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type HoverParams struct {
|
type HoverParams struct {
|
||||||
@@ -253,7 +255,7 @@ func HandleMessage(msg *JsonRpcMessage) {
|
|||||||
|
|
||||||
respond(msg.ID, map[string]any{
|
respond(msg.ID, map[string]any{
|
||||||
"capabilities": map[string]any{
|
"capabilities": map[string]any{
|
||||||
"textDocumentSync": 1, // Full sync
|
"textDocumentSync": 2, // Incremental sync
|
||||||
"hoverProvider": true,
|
"hoverProvider": true,
|
||||||
"definitionProvider": true,
|
"definitionProvider": true,
|
||||||
"referencesProvider": true,
|
"referencesProvider": true,
|
||||||
@@ -347,28 +349,76 @@ func HandleDidOpen(params DidOpenTextDocumentParams) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func HandleDidChange(params DidChangeTextDocumentParams) {
|
func HandleDidChange(params DidChangeTextDocumentParams) {
|
||||||
if len(params.ContentChanges) == 0 {
|
uri := params.TextDocument.URI
|
||||||
return
|
text, ok := Documents[uri]
|
||||||
|
if !ok {
|
||||||
|
// If not found, rely on full sync being first or error
|
||||||
}
|
}
|
||||||
text := params.ContentChanges[0].Text
|
|
||||||
Documents[params.TextDocument.URI] = text
|
for _, change := range params.ContentChanges {
|
||||||
path := uriToPath(params.TextDocument.URI)
|
if change.Range == nil {
|
||||||
|
text = change.Text
|
||||||
|
} else {
|
||||||
|
text = applyContentChange(text, change)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Documents[uri] = text
|
||||||
|
path := uriToPath(uri)
|
||||||
p := parser.NewParser(text)
|
p := parser.NewParser(text)
|
||||||
config, err := p.Parse()
|
config, err := p.Parse()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
publishParserError(params.TextDocument.URI, err)
|
publishParserError(uri, err)
|
||||||
} else {
|
} else {
|
||||||
publishParserError(params.TextDocument.URI, nil)
|
publishParserError(uri, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
if config != nil {
|
if config != nil {
|
||||||
Tree.AddFile(path, config)
|
Tree.AddFile(path, config)
|
||||||
Tree.ResolveReferences()
|
Tree.ResolveReferences()
|
||||||
runValidation(params.TextDocument.URI)
|
runValidation(uri)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func applyContentChange(text string, change TextDocumentContentChangeEvent) string {
|
||||||
|
startOffset := offsetAt(text, change.Range.Start)
|
||||||
|
endOffset := offsetAt(text, change.Range.End)
|
||||||
|
|
||||||
|
if startOffset == -1 || endOffset == -1 {
|
||||||
|
return text
|
||||||
|
}
|
||||||
|
|
||||||
|
return text[:startOffset] + change.Text + text[endOffset:]
|
||||||
|
}
|
||||||
|
|
||||||
|
func offsetAt(text string, pos Position) int {
|
||||||
|
line := 0
|
||||||
|
col := 0
|
||||||
|
for i, r := range text {
|
||||||
|
if line == pos.Line && col == pos.Character {
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
if line > pos.Line {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if r == '\n' {
|
||||||
|
line++
|
||||||
|
col = 0
|
||||||
|
} else {
|
||||||
|
if r >= 0x10000 {
|
||||||
|
col += 2
|
||||||
|
} else {
|
||||||
|
col++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if line == pos.Line && col == pos.Character {
|
||||||
|
return len(text)
|
||||||
|
}
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
func HandleFormatting(params DocumentFormattingParams) []TextEdit {
|
func HandleFormatting(params DocumentFormattingParams) []TextEdit {
|
||||||
uri := params.TextDocument.URI
|
uri := params.TextDocument.URI
|
||||||
text, ok := Documents[uri]
|
text, ok := Documents[uri]
|
||||||
@@ -646,7 +696,7 @@ func suggestGAMSignals(_ *index.ProjectNode, direction string) *CompletionList {
|
|||||||
|
|
||||||
dir := "NIL"
|
dir := "NIL"
|
||||||
if GlobalSchema != nil {
|
if GlobalSchema != nil {
|
||||||
classPath := cue.ParsePath(fmt.Sprintf("#Classes.%s.#direction", cls))
|
classPath := cue.ParsePath(fmt.Sprintf("#Classes.%s.#meta.direction", cls))
|
||||||
val := GlobalSchema.Value.LookupPath(classPath)
|
val := GlobalSchema.Value.LookupPath(classPath)
|
||||||
if val.Err() == nil {
|
if val.Err() == nil {
|
||||||
var s string
|
var s string
|
||||||
@@ -1161,7 +1211,20 @@ func formatNodeInfo(node *index.ProjectNode) string {
|
|||||||
curr := container
|
curr := container
|
||||||
for curr != nil {
|
for curr != nil {
|
||||||
if isGAM(curr) {
|
if isGAM(curr) {
|
||||||
gams = append(gams, curr.RealName)
|
suffix := ""
|
||||||
|
p := container
|
||||||
|
for p != nil && p != curr {
|
||||||
|
if p.Name == "InputSignals" {
|
||||||
|
suffix = " (Input)"
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if p.Name == "OutputSignals" {
|
||||||
|
suffix = " (Output)"
|
||||||
|
break
|
||||||
|
}
|
||||||
|
p = p.Parent
|
||||||
|
}
|
||||||
|
gams = append(gams, curr.RealName+suffix)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
curr = curr.Parent
|
curr = curr.Parent
|
||||||
@@ -1175,7 +1238,11 @@ func formatNodeInfo(node *index.ProjectNode) string {
|
|||||||
if n.Target == node {
|
if n.Target == node {
|
||||||
if n.Parent != nil && (n.Parent.Name == "InputSignals" || n.Parent.Name == "OutputSignals") {
|
if n.Parent != nil && (n.Parent.Name == "InputSignals" || n.Parent.Name == "OutputSignals") {
|
||||||
if n.Parent.Parent != nil && isGAM(n.Parent.Parent) {
|
if n.Parent.Parent != nil && isGAM(n.Parent.Parent) {
|
||||||
gams = append(gams, n.Parent.Parent.RealName)
|
suffix := " (Input)"
|
||||||
|
if n.Parent.Name == "OutputSignals" {
|
||||||
|
suffix = " (Output)"
|
||||||
|
}
|
||||||
|
gams = append(gams, n.Parent.Parent.RealName+suffix)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,8 +43,8 @@ package schema
|
|||||||
...
|
...
|
||||||
}
|
}
|
||||||
TimingDataSource: {
|
TimingDataSource: {
|
||||||
#multithreaded: bool | *false
|
#meta: multithreaded: bool | *false
|
||||||
#direction: "IN"
|
#meta: direction: "IN"
|
||||||
...
|
...
|
||||||
}
|
}
|
||||||
IOGAM: {
|
IOGAM: {
|
||||||
@@ -67,84 +67,84 @@ package schema
|
|||||||
FileDataSource: {
|
FileDataSource: {
|
||||||
Filename: string
|
Filename: string
|
||||||
Format?: string
|
Format?: string
|
||||||
#multithreaded: bool | *false
|
#meta: multithreaded: bool | *false
|
||||||
#direction: "INOUT"
|
#meta: direction: "INOUT"
|
||||||
...
|
...
|
||||||
}
|
}
|
||||||
LoggerDataSource: {
|
LoggerDataSource: {
|
||||||
#multithreaded: bool | *false
|
#meta: multithreaded: bool | *false
|
||||||
#direction: "OUT"
|
#meta: direction: "OUT"
|
||||||
...
|
...
|
||||||
}
|
}
|
||||||
DANStream: {
|
DANStream: {
|
||||||
Timeout?: int
|
Timeout?: int
|
||||||
#multithreaded: bool | *false
|
#meta: multithreaded: bool | *false
|
||||||
#direction: "OUT"
|
#meta: direction: "OUT"
|
||||||
...
|
...
|
||||||
}
|
}
|
||||||
EPICSCAInput: {
|
EPICSCAInput: {
|
||||||
#multithreaded: bool | *false
|
#meta: multithreaded: bool | *false
|
||||||
#direction: "IN"
|
#meta: direction: "IN"
|
||||||
...
|
...
|
||||||
}
|
}
|
||||||
EPICSCAOutput: {
|
EPICSCAOutput: {
|
||||||
#multithreaded: bool | *false
|
#meta: multithreaded: bool | *false
|
||||||
#direction: "OUT"
|
#meta: direction: "OUT"
|
||||||
...
|
...
|
||||||
}
|
}
|
||||||
EPICSPVAInput: {
|
EPICSPVAInput: {
|
||||||
#multithreaded: bool | *false
|
#meta: multithreaded: bool | *false
|
||||||
#direction: "IN"
|
#meta: direction: "IN"
|
||||||
...
|
...
|
||||||
}
|
}
|
||||||
EPICSPVAOutput: {
|
EPICSPVAOutput: {
|
||||||
#multithreaded: bool | *false
|
#meta: multithreaded: bool | *false
|
||||||
#direction: "OUT"
|
#meta: direction: "OUT"
|
||||||
...
|
...
|
||||||
}
|
}
|
||||||
SDNSubscriber: {
|
SDNSubscriber: {
|
||||||
Address: string
|
Address: string
|
||||||
Port: int
|
Port: int
|
||||||
Interface?: string
|
Interface?: string
|
||||||
#multithreaded: bool | *false
|
#meta: multithreaded: bool | *false
|
||||||
#direction: "IN"
|
#meta: direction: "IN"
|
||||||
...
|
...
|
||||||
}
|
}
|
||||||
SDNPublisher: {
|
SDNPublisher: {
|
||||||
Address: string
|
Address: string
|
||||||
Port: int
|
Port: int
|
||||||
Interface?: string
|
Interface?: string
|
||||||
#multithreaded: bool | *false
|
#meta: multithreaded: bool | *false
|
||||||
#direction: "OUT"
|
#meta: direction: "OUT"
|
||||||
...
|
...
|
||||||
}
|
}
|
||||||
UDPReceiver: {
|
UDPReceiver: {
|
||||||
Port: int
|
Port: int
|
||||||
Address?: string
|
Address?: string
|
||||||
#multithreaded: bool | *false
|
#meta: multithreaded: bool | *false
|
||||||
#direction: "IN"
|
#meta: direction: "IN"
|
||||||
...
|
...
|
||||||
}
|
}
|
||||||
UDPSender: {
|
UDPSender: {
|
||||||
Destination: string
|
Destination: string
|
||||||
#multithreaded: bool | *false
|
#meta: multithreaded: bool | *false
|
||||||
#direction: "OUT"
|
#meta: direction: "OUT"
|
||||||
...
|
...
|
||||||
}
|
}
|
||||||
FileReader: {
|
FileReader: {
|
||||||
Filename: string
|
Filename: string
|
||||||
Format?: string
|
Format?: string
|
||||||
Interpolate?: string
|
Interpolate?: string
|
||||||
#multithreaded: bool | *false
|
#meta: multithreaded: bool | *false
|
||||||
#direction: "IN"
|
#meta: direction: "IN"
|
||||||
...
|
...
|
||||||
}
|
}
|
||||||
FileWriter: {
|
FileWriter: {
|
||||||
Filename: string
|
Filename: string
|
||||||
Format?: string
|
Format?: string
|
||||||
StoreOnTrigger?: int
|
StoreOnTrigger?: int
|
||||||
#multithreaded: bool | *false
|
#meta: multithreaded: bool | *false
|
||||||
#direction: "OUT"
|
#meta: direction: "OUT"
|
||||||
...
|
...
|
||||||
}
|
}
|
||||||
OrderedClass: {
|
OrderedClass: {
|
||||||
@@ -187,8 +187,8 @@ package schema
|
|||||||
TriggeredIOGAM: {...}
|
TriggeredIOGAM: {...}
|
||||||
WaveformGAM: {...}
|
WaveformGAM: {...}
|
||||||
DAN: {
|
DAN: {
|
||||||
#multithreaded: bool | *false
|
#meta: multithreaded: bool | *false
|
||||||
#direction: "OUT"
|
#meta: direction: "OUT"
|
||||||
...
|
...
|
||||||
}
|
}
|
||||||
LinuxTimer: {
|
LinuxTimer: {
|
||||||
@@ -199,13 +199,13 @@ package schema
|
|||||||
CPUMask?: int
|
CPUMask?: int
|
||||||
TimeProvider?: {...}
|
TimeProvider?: {...}
|
||||||
Signals: {...}
|
Signals: {...}
|
||||||
#multithreaded: bool | *false
|
#meta: multithreaded: bool | *false
|
||||||
#direction: "IN"
|
#meta: direction: "IN"
|
||||||
...
|
...
|
||||||
}
|
}
|
||||||
LinkDataSource: {
|
LinkDataSource: {
|
||||||
#multithreaded: bool | *false
|
#meta: multithreaded: bool | *false
|
||||||
#direction: "INOUT"
|
#meta: direction: "INOUT"
|
||||||
...
|
...
|
||||||
}
|
}
|
||||||
MDSReader: {
|
MDSReader: {
|
||||||
@@ -213,8 +213,8 @@ package schema
|
|||||||
ShotNumber: int
|
ShotNumber: int
|
||||||
Frequency: float | int
|
Frequency: float | int
|
||||||
Signals: {...}
|
Signals: {...}
|
||||||
#multithreaded: bool | *false
|
#meta: multithreaded: bool | *false
|
||||||
#direction: "IN"
|
#meta: direction: "IN"
|
||||||
...
|
...
|
||||||
}
|
}
|
||||||
MDSWriter: {
|
MDSWriter: {
|
||||||
@@ -230,74 +230,74 @@ package schema
|
|||||||
NumberOfPostTriggers?: int
|
NumberOfPostTriggers?: int
|
||||||
Signals: {...}
|
Signals: {...}
|
||||||
Messages?: {...}
|
Messages?: {...}
|
||||||
#multithreaded: bool | *false
|
#meta: multithreaded: bool | *false
|
||||||
#direction: "OUT"
|
#meta: direction: "OUT"
|
||||||
...
|
...
|
||||||
}
|
}
|
||||||
NI1588TimeStamp: {
|
NI1588TimeStamp: {
|
||||||
#multithreaded: bool | *false
|
#meta: multithreaded: bool | *false
|
||||||
#direction: "IN"
|
#meta: direction: "IN"
|
||||||
...
|
...
|
||||||
}
|
}
|
||||||
NI6259ADC: {
|
NI6259ADC: {
|
||||||
#multithreaded: bool | *false
|
#meta: multithreaded: bool | *false
|
||||||
#direction: "IN"
|
#meta: direction: "IN"
|
||||||
...
|
...
|
||||||
}
|
}
|
||||||
NI6259DAC: {
|
NI6259DAC: {
|
||||||
#multithreaded: bool | *false
|
#meta: multithreaded: bool | *false
|
||||||
#direction: "OUT"
|
#meta: direction: "OUT"
|
||||||
...
|
...
|
||||||
}
|
}
|
||||||
NI6259DIO: {
|
NI6259DIO: {
|
||||||
#multithreaded: bool | *false
|
#meta: multithreaded: bool | *false
|
||||||
#direction: "INOUT"
|
#meta: direction: "INOUT"
|
||||||
...
|
...
|
||||||
}
|
}
|
||||||
NI6368ADC: {
|
NI6368ADC: {
|
||||||
#multithreaded: bool | *false
|
#meta: multithreaded: bool | *false
|
||||||
#direction: "IN"
|
#meta: direction: "IN"
|
||||||
...
|
...
|
||||||
}
|
}
|
||||||
NI6368DAC: {
|
NI6368DAC: {
|
||||||
#multithreaded: bool | *false
|
#meta: multithreaded: bool | *false
|
||||||
#direction: "OUT"
|
#meta: direction: "OUT"
|
||||||
...
|
...
|
||||||
}
|
}
|
||||||
NI6368DIO: {
|
NI6368DIO: {
|
||||||
#multithreaded: bool | *false
|
#meta: multithreaded: bool | *false
|
||||||
#direction: "INOUT"
|
#meta: direction: "INOUT"
|
||||||
...
|
...
|
||||||
}
|
}
|
||||||
NI9157CircularFifoReader: {
|
NI9157CircularFifoReader: {
|
||||||
#multithreaded: bool | *false
|
#meta: multithreaded: bool | *false
|
||||||
#direction: "IN"
|
#meta: direction: "IN"
|
||||||
...
|
...
|
||||||
}
|
}
|
||||||
NI9157MxiDataSource: {
|
NI9157MxiDataSource: {
|
||||||
#multithreaded: bool | *false
|
#meta: multithreaded: bool | *false
|
||||||
#direction: "INOUT"
|
#meta: direction: "INOUT"
|
||||||
...
|
...
|
||||||
}
|
}
|
||||||
OPCUADSInput: {
|
OPCUADSInput: {
|
||||||
#multithreaded: bool | *false
|
#meta: multithreaded: bool | *false
|
||||||
#direction: "IN"
|
#meta: direction: "IN"
|
||||||
...
|
...
|
||||||
}
|
}
|
||||||
OPCUADSOutput: {
|
OPCUADSOutput: {
|
||||||
#multithreaded: bool | *false
|
#meta: multithreaded: bool | *false
|
||||||
#direction: "OUT"
|
#meta: direction: "OUT"
|
||||||
...
|
...
|
||||||
}
|
}
|
||||||
RealTimeThreadAsyncBridge: {
|
RealTimeThreadAsyncBridge: {
|
||||||
#direction: "INOUT"
|
#meta: direction: "INOUT"
|
||||||
#multithreaded: bool | true
|
#meta: multithreaded: bool | true
|
||||||
...
|
...
|
||||||
}
|
}
|
||||||
RealTimeThreadSynchronisation: {...}
|
RealTimeThreadSynchronisation: {...}
|
||||||
UARTDataSource: {
|
UARTDataSource: {
|
||||||
#multithreaded: bool | *false
|
#meta: multithreaded: bool | *false
|
||||||
#direction: "INOUT"
|
#meta: direction: "INOUT"
|
||||||
...
|
...
|
||||||
}
|
}
|
||||||
BaseLib2Wrapper: {...}
|
BaseLib2Wrapper: {...}
|
||||||
@@ -307,8 +307,8 @@ package schema
|
|||||||
OPCUA: {...}
|
OPCUA: {...}
|
||||||
SysLogger: {...}
|
SysLogger: {...}
|
||||||
GAMDataSource: {
|
GAMDataSource: {
|
||||||
#multithreaded: bool | *false
|
#meta: multithreaded: bool | *false
|
||||||
#direction: "INOUT"
|
#meta: direction: "INOUT"
|
||||||
...
|
...
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -315,8 +315,8 @@ func (v *Validator) validateGAMSignal(gamNode, signalNode *index.ProjectNode, di
|
|||||||
dsClass := v.getNodeClass(dsNode)
|
dsClass := v.getNodeClass(dsNode)
|
||||||
if dsClass != "" {
|
if dsClass != "" {
|
||||||
// Lookup class definition in Schema
|
// Lookup class definition in Schema
|
||||||
// path: #Classes.ClassName.direction
|
// path: #Classes.ClassName.#meta.direction
|
||||||
path := cue.ParsePath(fmt.Sprintf("#Classes.%s.#direction", dsClass))
|
path := cue.ParsePath(fmt.Sprintf("#Classes.%s.#meta.direction", dsClass))
|
||||||
val := v.Schema.Value.LookupPath(path)
|
val := v.Schema.Value.LookupPath(path)
|
||||||
|
|
||||||
if val.Err() == nil {
|
if val.Err() == nil {
|
||||||
@@ -875,10 +875,12 @@ func (v *Validator) getGAMDataSources(gam *index.ProjectNode) []*index.ProjectNo
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (v *Validator) isMultithreaded(ds *index.ProjectNode) bool {
|
func (v *Validator) isMultithreaded(ds *index.ProjectNode) bool {
|
||||||
fields := v.getFields(ds)
|
if meta, ok := ds.Children["#meta"]; ok {
|
||||||
if mt, ok := fields["#multithreaded"]; ok && len(mt) > 0 {
|
fields := v.getFields(meta)
|
||||||
val := v.getFieldValue(mt[0])
|
if mt, ok := fields["multithreaded"]; ok && len(mt) > 0 {
|
||||||
return val == "true"
|
val := v.getFieldValue(mt[0])
|
||||||
|
return val == "true"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|||||||
66
test/index_test.go
Normal file
66
test/index_test.go
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
package integration
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/marte-community/marte-dev-tools/internal/index"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestNodeMap(t *testing.T) {
|
||||||
|
pt := index.NewProjectTree()
|
||||||
|
root := pt.Root
|
||||||
|
|
||||||
|
// Create structure: +A -> +B -> +C
|
||||||
|
nodeA := &index.ProjectNode{Name: "A", RealName: "+A", Children: make(map[string]*index.ProjectNode), Parent: root}
|
||||||
|
root.Children["A"] = nodeA
|
||||||
|
|
||||||
|
nodeB := &index.ProjectNode{Name: "B", RealName: "+B", Children: make(map[string]*index.ProjectNode), Parent: nodeA}
|
||||||
|
nodeA.Children["B"] = nodeB
|
||||||
|
|
||||||
|
nodeC := &index.ProjectNode{Name: "C", RealName: "+C", Children: make(map[string]*index.ProjectNode), Parent: nodeB}
|
||||||
|
nodeB.Children["C"] = nodeC
|
||||||
|
|
||||||
|
// Rebuild Index
|
||||||
|
pt.RebuildIndex()
|
||||||
|
|
||||||
|
// Find by Name
|
||||||
|
found := pt.FindNode(root, "C", nil)
|
||||||
|
if found != nodeC {
|
||||||
|
t.Errorf("FindNode(C) failed. Got %v, want %v", found, nodeC)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find by RealName
|
||||||
|
found = pt.FindNode(root, "+C", nil)
|
||||||
|
if found != nodeC {
|
||||||
|
t.Errorf("FindNode(+C) failed. Got %v, want %v", found, nodeC)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find by Path
|
||||||
|
found = pt.FindNode(root, "A.B.C", nil)
|
||||||
|
if found != nodeC {
|
||||||
|
t.Errorf("FindNode(A.B.C) failed. Got %v, want %v", found, nodeC)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find by Path with RealName
|
||||||
|
found = pt.FindNode(root, "+A.+B.+C", nil)
|
||||||
|
if found != nodeC {
|
||||||
|
t.Errorf("FindNode(+A.+B.+C) failed. Got %v, want %v", found, nodeC)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestResolveReferencesWithMap(t *testing.T) {
|
||||||
|
pt := index.NewProjectTree()
|
||||||
|
root := pt.Root
|
||||||
|
|
||||||
|
nodeA := &index.ProjectNode{Name: "A", RealName: "+A", Children: make(map[string]*index.ProjectNode), Parent: root}
|
||||||
|
root.Children["A"] = nodeA
|
||||||
|
|
||||||
|
ref := index.Reference{Name: "A", File: "test.marte"}
|
||||||
|
pt.References = append(pt.References, ref)
|
||||||
|
|
||||||
|
pt.ResolveReferences()
|
||||||
|
|
||||||
|
if pt.References[0].Target != nodeA {
|
||||||
|
t.Error("ResolveReferences failed to resolve A")
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -20,7 +20,7 @@ func TestSuggestSignalsRobustness(t *testing.T) {
|
|||||||
custom := []byte(`
|
custom := []byte(`
|
||||||
package schema
|
package schema
|
||||||
#Classes: {
|
#Classes: {
|
||||||
InOutReader: { #direction: "INOUT" }
|
InOutReader: { #meta: direction: "INOUT" }
|
||||||
}
|
}
|
||||||
`)
|
`)
|
||||||
val := lsp.GlobalSchema.Context.CompileBytes(custom)
|
val := lsp.GlobalSchema.Context.CompileBytes(custom)
|
||||||
|
|||||||
@@ -26,8 +26,10 @@ func TestLSPValidationThreading(t *testing.T) {
|
|||||||
Class = ReferenceContainer
|
Class = ReferenceContainer
|
||||||
+SharedDS = {
|
+SharedDS = {
|
||||||
Class = GAMDataSource
|
Class = GAMDataSource
|
||||||
#direction = "INOUT"
|
#meta = {
|
||||||
#multithreaded = false
|
direction = "INOUT"
|
||||||
|
multithreaded = false
|
||||||
|
}
|
||||||
Signals = {
|
Signals = {
|
||||||
Sig1 = { Type = uint32 }
|
Sig1 = { Type = uint32 }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,16 +15,20 @@ func TestDataSourceThreadingValidation(t *testing.T) {
|
|||||||
Class = ReferenceContainer
|
Class = ReferenceContainer
|
||||||
+SharedDS = {
|
+SharedDS = {
|
||||||
Class = GAMDataSource
|
Class = GAMDataSource
|
||||||
#direction = "INOUT"
|
#meta = {
|
||||||
#multithreaded = false
|
direction = "INOUT"
|
||||||
|
multithreaded = false
|
||||||
|
}
|
||||||
Signals = {
|
Signals = {
|
||||||
Sig1 = { Type = uint32 }
|
Sig1 = { Type = uint32 }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+MultiDS = {
|
+MultiDS = {
|
||||||
Class = GAMDataSource
|
Class = GAMDataSource
|
||||||
#direction = "INOUT"
|
#meta = {
|
||||||
#multithreaded = true
|
direction = "INOUT"
|
||||||
|
multithreaded = true
|
||||||
|
}
|
||||||
Signals = {
|
Signals = {
|
||||||
Sig1 = { Type = uint32 }
|
Sig1 = { Type = uint32 }
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user