private void AddSemanticToken(int startIdx, int stopIdx, string tokenType, params string[] tokenModifiers) { if (startIdx < 0 || stopIdx < 0) { return; } if (string.IsNullOrEmpty(tokenType)) { return; } var t = Array.IndexOf(BHLSemanticTokens.semanticTokenTypes, tokenType); if (t < 0) { return; } var nextStart = document.GetLineColumn(next); var lineColumnSymbol = document.GetLineColumn(startIdx); var diffLine = lineColumnSymbol.Item1 - nextStart.Item1; var diffColumn = diffLine != 0 ? lineColumnSymbol.Item2 : lineColumnSymbol.Item2 - nextStart.Item2; int bitTokenModifiers = 0; for (int i = 0; i < tokenModifiers.Length; i++) { var idx = Array.IndexOf(BHLSemanticTokens.semanticTokenModifiers, tokenModifiers[i]); bitTokenModifiers |= (int)Math.Pow(2, idx); } // line dataSemanticTokens.Add((uint)diffLine); // startChar dataSemanticTokens.Add((uint)diffColumn); // length dataSemanticTokens.Add((uint)(stopIdx - startIdx + 1)); // tokenType dataSemanticTokens.Add((uint)t); // tokenModifiers dataSemanticTokens.Add((uint)bitTokenModifiers); next = startIdx; }
/** * The result type LocationLink[] got introduced with version 3.14.0 * and depends on the corresponding client capability textDocument.definition.linkSupport. */ public override RpcResult GotoDefinition(DefinitionParams args) { BHLSPWorkspace.self.TryAddDocument(args.textDocument.uri); if (BHLSPWorkspace.self.FindDocument(args.textDocument.uri) is BHLTextDocument document) { int line = (int)args.position.line; int character = (int)args.position.character; int idx = document.GetIndex(line, character); bhlParser.FuncDeclContext funcDecl = null; BHLTextDocument funcDeclBhlDocument = null; bhlParser.CallExpContext callExp = null; bhlParser.MemberAccessContext memberAccess = null; bhlParser.TypeContext type = null; bhlParser.StatementContext statement = null; foreach (IParseTree node in BHLSPUtil.DFS(document.ToParser().program())) { if (node is ParserRuleContext prc) { if (prc.Start.StartIndex <= idx && idx <= prc.Stop.StopIndex) { funcDecl = prc as bhlParser.FuncDeclContext; callExp = prc as bhlParser.CallExpContext; memberAccess = prc as bhlParser.MemberAccessContext; type = prc as bhlParser.TypeContext; statement = prc as bhlParser.StatementContext; break; } } } if (funcDecl == null) { string classTypeName = string.Empty; string memberClassName = string.Empty; if (type?.NAME() != null) { classTypeName = type.NAME().GetText(); } else if (memberAccess != null) { bhlParser.CallExpContext callExpMemberAccess = null; bhlParser.FuncDeclContext memberAccessParentFuncDecl = null; memberClassName = memberAccess.NAME().GetText(); for (RuleContext parent = memberAccess.Parent; parent != null; parent = parent.Parent) { if (callExpMemberAccess == null && parent is bhlParser.CallExpContext) { callExpMemberAccess = parent as bhlParser.CallExpContext; } if (parent is bhlParser.FuncDeclContext) { memberAccessParentFuncDecl = parent as bhlParser.FuncDeclContext; break; } } if (callExpMemberAccess != null) { string callExpMemberAccessName = callExpMemberAccess.NAME().GetText(); if (memberAccessParentFuncDecl?.NAME() != null) { foreach (IParseTree node in BHLSPUtil.DFS(memberAccessParentFuncDecl)) { if (node is bhlParser.FuncParamDeclareContext funcParamDeclare) { bhlParser.TypeContext funcParamDeclareType = funcParamDeclare.type(); if (funcParamDeclareType.funcType() != null || funcParamDeclareType.ARR() != null) { continue; } if (funcParamDeclare.NAME()?.GetText() == callExpMemberAccessName) { classTypeName = funcParamDeclareType.GetText(); break; } } if (node is bhlParser.VarDeclareContext varDeclare && varDeclare?.NAME().GetText() == callExpMemberAccessName) { classTypeName = varDeclare.type().NAME().GetText(); break; } } } } } if (!string.IsNullOrEmpty(classTypeName)) { bhlParser.ClassDeclContext classDecl = null; BHLTextDocument classDeclBhlDocument = null; foreach (var doc in BHLSPWorkspace.self.ForEachBhlImports(document)) { if (doc.ClassDecls.ContainsKey(classTypeName)) { classDecl = doc.ClassDecls[classTypeName]; classDeclBhlDocument = doc; break; } } if (classDecl != null) { bhlParser.ClassMemberContext classMember = null; if (!string.IsNullOrEmpty(memberClassName)) { foreach (var classMemberContext in classDecl.classBlock().classMembers().classMember()) { if (classMemberContext.funcDecl()?.NAME()?.GetText() != null) { if (classMemberContext.funcDecl().NAME().GetText() == memberClassName) { classMember = classMemberContext; break; } } if (classMemberContext.varDeclare()?.NAME()?.GetText() != null) { if (classMemberContext.varDeclare().NAME().GetText() == memberClassName) { classMember = classMemberContext; break; } } } } int classDeclIdx = classMember?.Start.StartIndex ?? classDecl.Start.StartIndex; var start = classDeclBhlDocument.GetLineColumn(classDeclIdx); var startPos = new Position { line = (uint)start.Item1, character = (uint)start.Item2 }; return(RpcResult.Success(new Location { uri = classDeclBhlDocument.uri, range = new Range { start = startPos, end = startPos } })); } } if (callExp != null) { string callExpName = callExp.NAME().GetText(); foreach (var doc in BHLSPWorkspace.self.ForEachBhlImports(document)) { if (doc.FuncDecls.ContainsKey(callExpName)) { funcDecl = doc.FuncDecls[callExpName]; funcDeclBhlDocument = doc; break; } } } if (statement != null && funcDecl == null) { string funcName = string.Empty; string pattern = @"([a-zA-Z_][a-zA-Z_0-9]*)(\({1}.*?)"; MatchCollection matches = Regex.Matches(statement.GetText(), pattern, RegexOptions.Multiline); for (int i = 0; i < matches.Count; i++) { var m = matches[i]; if (m.Groups.Count > 1) { Group g = m.Groups[1]; funcName = g.Value; break; } } if (!string.IsNullOrEmpty(funcName)) { foreach (var doc in BHLSPWorkspace.self.ForEachBhlImports(document)) { if (doc.FuncDecls.ContainsKey(funcName)) { funcDecl = doc.FuncDecls[funcName]; funcDeclBhlDocument = doc; break; } } } } } else { funcDeclBhlDocument = document; } if (funcDecl != null) { var start = funcDeclBhlDocument.GetLineColumn(funcDecl.Start.StartIndex); var startPos = new Position { line = (uint)start.Item1, character = (uint)start.Item2 }; return(RpcResult.Success(new Location { uri = funcDeclBhlDocument.uri, range = new Range { start = startPos, end = startPos } })); } } return(RpcResult.Success()); }