Skip to content

Commit 3a27918

Browse files
authored
Merge pull request #1 from joshraphael/structured_data
Structured data
2 parents 76748bd + 4968269 commit 3a27918

File tree

8 files changed

+1026
-214
lines changed

8 files changed

+1026
-214
lines changed

README.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,9 @@ C:\Users\joshraphael\rascript-language-server_v0.0.1_win-x64.exe
3030
- Syntax Highlighting - Custom RAScript syntax highlighting using TextMate.
3131
- Function navigation - Jump to a functions defintion.
3232
- Code Completion - Completion results appear for symbols as you type.
33-
- Hover Info - Documentation appears when you hover over a function.
33+
- Hover Info - Documentation appears when you hover over a function or class.
3434

3535
## Projects Using rascript-language-server
3636
- [vscode-rascript](https://github.com/joshraphael/vscode-rascript) - VSCode language client for RAScript.
37-
- [sublime-rascript](https://github.com/joshraphael/sublime-rascript) - SublimeText language client for RAScript.
37+
- [sublime-rascript](https://github.com/joshraphael/sublime-rascript) - SublimeText language client for RAScript.
38+
- [npp-rascript](https://github.com/joshraphael/npp-rascript) - Notepad++ language client for RAScript.

src/BufferManager.cs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
using System.Collections.Concurrent;
22
using System.Text;
3-
using System.Threading.Tasks;
4-
using OmniSharp.Extensions.LanguageServer.Protocol.Window;
53
using RASharp;
64
using RASharp.Models;
75

src/CompletionProvider.cs

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,7 @@
1-
using OmniSharp.Extensions.LanguageServer.Protocol;
21
using OmniSharp.Extensions.LanguageServer.Protocol.Client.Capabilities;
32
using OmniSharp.Extensions.LanguageServer.Protocol.Document;
43
using OmniSharp.Extensions.LanguageServer.Protocol.Models;
54
using OmniSharp.Extensions.LanguageServer.Protocol.Server;
6-
using OmniSharp.Extensions.LanguageServer.Protocol.Window;
7-
using Range = OmniSharp.Extensions.LanguageServer.Protocol.Models.Range;
85

96
namespace RAScriptLanguageServer
107
{
@@ -37,13 +34,31 @@ public override Task<CompletionList> Handle(CompletionParams request, Cancellati
3734
List<CompletionItem> items = new List<CompletionItem>();
3835
if (parser != null)
3936
{
40-
foreach (var k in parser.GetKeywords())
37+
HashSet<string> functionSet = [.. parser.completionFunctions];
38+
foreach (string fnName in functionSet)
4139
{
42-
CompletionItemKind kind = parser.GetKeywordCompletionItemKind(k) ?? CompletionItemKind.Text;
4340
items.Add(new CompletionItem()
4441
{
45-
Label = k,
46-
Kind = kind,
42+
Label = fnName,
43+
Kind = CompletionItemKind.Function,
44+
});
45+
}
46+
HashSet<string> variableSet = [.. parser.completionVariables];
47+
foreach (string varName in variableSet)
48+
{
49+
items.Add(new CompletionItem()
50+
{
51+
Label = varName,
52+
Kind = CompletionItemKind.Variable,
53+
});
54+
}
55+
HashSet<string> classSet = [.. parser.completionClasses];
56+
foreach (string className in classSet)
57+
{
58+
items.Add(new CompletionItem()
59+
{
60+
Label = className,
61+
Kind = CompletionItemKind.Class,
4762
});
4863
}
4964
}

src/DefinitionProvider.cs

Lines changed: 25 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
1-
using OmniSharp.Extensions.LanguageServer.Protocol;
21
using OmniSharp.Extensions.LanguageServer.Protocol.Client.Capabilities;
32
using OmniSharp.Extensions.LanguageServer.Protocol.Document;
43
using OmniSharp.Extensions.LanguageServer.Protocol.Models;
54
using OmniSharp.Extensions.LanguageServer.Protocol.Server;
6-
using OmniSharp.Extensions.LanguageServer.Protocol.Window;
75
using Range = OmniSharp.Extensions.LanguageServer.Protocol.Models.Range;
86

97
namespace RAScriptLanguageServer
@@ -26,24 +24,37 @@ public DefinitionProvider(ILanguageServerFacade router, BufferManager bufferMana
2624
public override Task<LocationOrLocationLinks?> Handle(DefinitionParams request, CancellationToken cancellationToken)
2725
{
2826
var documentPath = request.TextDocument.Uri.ToString();
29-
var line = request.Position.Line;
30-
var character = request.Position.Character;
3127
var buffer = _bufferManager.GetBuffer(documentPath);
3228
var txt = buffer?.GetDocumentText();
33-
if (txt != null && txt.Length > 0)
29+
if (buffer != null && txt != null && txt.Length > 0)
3430
{
35-
var word = buffer?.GetParser().GetWordAtPosition(txt, line, character);
36-
if (word != null && word.Length != 0)
31+
var word = buffer.GetParser().GetWordAtPosition(request.Position);
32+
if (word != null && word.Word.Length != 0)
3733
{
38-
Position? pos = buffer?.GetParser().GetLinkLocation(word);
39-
if (pos != null)
34+
int startOffset = buffer.GetParser().GetOffsetAt(word.Start);
35+
int endOffset = buffer.GetParser().GetOffsetAt(word.End);
36+
string hoverClass = buffer.GetParser().DetectClass(startOffset);
37+
if (txt[endOffset+1] != '(')
4038
{
41-
var location = new LocationOrLocationLinks(new LocationOrLocationLink(new Location
39+
return Task.FromResult<LocationOrLocationLinks?>(null); // not a function (maybe string, or just varaible named the same)
40+
}
41+
int origWordOffset = buffer.GetParser().GetOffsetAt(request.Position);
42+
List<ClassFunction>? list = buffer.GetParser().GetClassFunctionDefinitions(word.Word);
43+
if (list != null)
44+
{
45+
WordScope scope = buffer.GetParser().GetScope(word.Start);
46+
List<ClassFunction> filteredList = list.Where(buffer.GetParser().ClassFilter(scope.Global, scope.UsingThis, hoverClass)).ToList();
47+
// can only link to one location, so anything that has multiple definitions wont work for code jumping
48+
if (filteredList.Count == 1)
4249
{
43-
Uri = request.TextDocument.Uri,
44-
Range = new Range(pos, pos)
45-
}));
46-
return Task.FromResult<LocationOrLocationLinks?>(location);
50+
ClassFunction el = filteredList[0];
51+
LocationOrLocationLinks location = new LocationOrLocationLinks(new LocationOrLocationLink(new Location
52+
{
53+
Uri = request.TextDocument.Uri,
54+
Range = new Range(el.Pos, el.Pos)
55+
}));
56+
return Task.FromResult<LocationOrLocationLinks?>(location);
57+
}
4758
}
4859
}
4960
}

src/FunctionDefinitions.cs

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1078,12 +1078,4 @@ public FunctionDefinitions()
10781078
};
10791079
}
10801080
}
1081-
1082-
public class FunctionDefinition
1083-
{
1084-
public required string Key { get; set; }
1085-
public required string URL { get; set; }
1086-
public required string[] Args { get; set; }
1087-
public required string[] CommentDoc { get; set; }
1088-
}
10891081
}

src/HoverProvider.cs

Lines changed: 139 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@
22
using OmniSharp.Extensions.LanguageServer.Protocol.Server;
33
using OmniSharp.Extensions.LanguageServer.Protocol.Client.Capabilities;
44
using OmniSharp.Extensions.LanguageServer.Protocol.Document;
5-
using OmniSharp.Extensions.LanguageServer.Protocol.Window;
6-
using System.Text;
75

86
namespace RAScriptLanguageServer
97
{
@@ -23,28 +21,153 @@ class HoverProvider(ILanguageServerFacade router, BufferManager bufferManager) :
2321
public override Task<Hover?> Handle(HoverParams request, CancellationToken cancellationToken)
2422
{
2523
var documentPath = request.TextDocument.Uri.ToString();
26-
var line = request.Position.Line;
27-
var character = request.Position.Character;
24+
var t = request.Position;
2825
var buffer = _bufferManager.GetBuffer(documentPath);
2926
var txt = buffer?.GetDocumentText();
30-
if (txt != null && txt.Length > 0)
27+
if (buffer != null && txt != null && txt.Length > 0)
3128
{
32-
var word = buffer?.GetParser().GetWordAtPosition(txt, line, character);
33-
if (word != null && word.Length != 0)
29+
var word = buffer.GetParser().GetWordAtPosition(request.Position);
30+
if (word != null && word.Word.Length != 0)
3431
{
35-
var hoverText = buffer?.GetParser().GetHoverText(word);
36-
if (hoverText != null && hoverText.Length > 0)
32+
int startingOffset = buffer.GetParser().GetOffsetAt(word.Start);
33+
int endingOffset = buffer.GetParser().GetOffsetAt(word.End);
34+
string hoverClass = buffer.GetParser().DetectClass(startingOffset);
35+
int offset = startingOffset - 1;
36+
37+
// Special case: this keyword should show the class hover info
38+
if (word.Word == "this")
3739
{
38-
var content = new List<MarkedString>();
39-
foreach (var l in hoverText)
40+
List<HoverData>? classDefinitions = buffer.GetParser().GetHoverData(hoverClass);
41+
if (classDefinitions != null)
4042
{
41-
content.Add(new MarkedString(l));
43+
foreach (HoverData hoverData in classDefinitions)
44+
{
45+
if (hoverData.ClassName == "")
46+
{
47+
var content = new List<MarkedString>();
48+
foreach (var l in hoverData.Lines)
49+
{
50+
content.Add(new MarkedString(l));
51+
}
52+
Hover result = new()
53+
{
54+
Contents = new MarkedStringsOrMarkupContent(content)
55+
};
56+
return Task.FromResult<Hover?>(result);
57+
}
58+
}
4259
}
43-
Hover result = new()
60+
}
61+
WordScope scope = buffer.GetParser().GetScope(word.Start);
62+
List<HoverData>? definitions = buffer.GetParser().GetHoverData(word.Word);
63+
if (definitions != null)
64+
{
65+
WordType wordType = buffer.GetParser().GetWordType(word);
66+
if (!wordType.Function && !wordType.Class && !wordType.CodeNote)
4467
{
45-
Contents = new MarkedStringsOrMarkupContent(content.ToArray())
46-
};
47-
return Task.FromResult<Hover?>(result);
68+
// only provide hover data for code notes, classes and functions
69+
return Task.FromResult<Hover?>(null);
70+
}
71+
// if we are hovering over the actual function signature itself, find it and return it
72+
foreach (HoverData definition in definitions)
73+
{
74+
// magic number 9 here is length of word function plus a space in between the function name
75+
if (startingOffset >= definition.Index && startingOffset <= definition.Index + 9 + definition.Key.Length)
76+
{
77+
var content = new List<MarkedString>();
78+
foreach (var l in definition.Lines)
79+
{
80+
content.Add(new MarkedString(l));
81+
}
82+
Hover result = new()
83+
{
84+
Contents = new MarkedStringsOrMarkupContent(content)
85+
};
86+
return Task.FromResult<Hover?>(result);
87+
}
88+
}
89+
90+
// determine list of definitions for function calls found in code bodies
91+
List<HoverData> filteredDefinitions = new List<HoverData>();
92+
foreach (HoverData definition in definitions)
93+
{
94+
if (scope.Global)
95+
{
96+
if (definition.ClassName == "")
97+
{
98+
// this should only be one occurence, but we can handle multiple
99+
filteredDefinitions.Add(definition);
100+
}
101+
}
102+
else
103+
{
104+
if (definition.ClassName != "")
105+
{
106+
// Special case: we can determine the exact definition is the definition if using this.<className>
107+
if (scope.UsingThis && hoverClass == definition.ClassName)
108+
{
109+
var content = new List<MarkedString>();
110+
foreach (var l in definition.Lines)
111+
{
112+
content.Add(new MarkedString(l));
113+
}
114+
Hover result = new()
115+
{
116+
Contents = new MarkedStringsOrMarkupContent(content)
117+
};
118+
return Task.FromResult<Hover?>(result);
119+
}
120+
// if its a function, further filter down by arg list length
121+
// otherwise just append if its a class
122+
if (wordType.Function)
123+
{
124+
int numArgs = buffer.GetParser().CountArgsAt(endingOffset);
125+
if (numArgs == definition.Args.Length)
126+
{
127+
filteredDefinitions.Add(definition);
128+
}
129+
}
130+
else
131+
{
132+
filteredDefinitions.Add(definition);
133+
}
134+
}
135+
}
136+
}
137+
if (filteredDefinitions.Count == 1)
138+
{
139+
HoverData definition = filteredDefinitions[0];
140+
var content = new List<MarkedString>();
141+
foreach (var l in definition.Lines)
142+
{
143+
content.Add(new MarkedString(l));
144+
}
145+
Hover result = new()
146+
{
147+
Contents = new MarkedStringsOrMarkupContent(content)
148+
};
149+
return Task.FromResult<Hover?>(result);
150+
}
151+
else
152+
{
153+
// Special case: more than one functions in different classes are named the same and we cant determine the exact hover data
154+
string[] lines = [];
155+
foreach (HoverData defintion in filteredDefinitions)
156+
{
157+
lines = lines.Concat(defintion.Lines).ToArray();
158+
}
159+
HoverData definition = filteredDefinitions[0];
160+
var content = new List<MarkedString>();
161+
foreach (var l in lines)
162+
{
163+
content.Add(new MarkedString(l));
164+
}
165+
Hover result = new()
166+
{
167+
Contents = new MarkedStringsOrMarkupContent(content)
168+
};
169+
return Task.FromResult<Hover?>(result);
170+
}
48171
}
49172
}
50173
}

src/Models.cs

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
using OmniSharp.Extensions.LanguageServer.Protocol.Models;
2+
3+
namespace RAScriptLanguageServer
4+
{
5+
public class ClassScope
6+
{
7+
public required int Start { get; set; }
8+
public required int End { get; set; }
9+
public required Dictionary<string, FunctionDefinition> Functions { get; set; }
10+
public required string[] ConstructorArgs { get; set; }
11+
}
12+
public class CommentBounds
13+
{
14+
public required int Start { get; set; }
15+
public required int End { get; set; }
16+
public required string Type { get; set; }
17+
public required string Raw { get; set; }
18+
}
19+
public class FunctionDefinition
20+
{
21+
public required string Key { get; set; }
22+
public required string URL { get; set; }
23+
public required string[] Args { get; set; }
24+
public required string[] CommentDoc { get; set; }
25+
}
26+
27+
public class ClassFunction
28+
{
29+
public required string ClassName { get; set; }
30+
public required string Name { get; set; }
31+
public required Position Pos { get; set; }
32+
public required string[] Args { get; set; }
33+
}
34+
35+
public class HoverData
36+
{
37+
public required string Key { get; set; }
38+
public required int Index { get; set; }
39+
public required string Type { get; set; }
40+
public required string ClassName { get; set; }
41+
public required string[] Args { get; set; }
42+
public required string[] Lines { get; set; }
43+
}
44+
45+
public class WordLocation
46+
{
47+
public required string Word { get; set; }
48+
public required Position Start { get; set; }
49+
public required Position End { get; set; }
50+
}
51+
52+
public class WordScope
53+
{
54+
public required bool Global { get; set; }
55+
public required bool UsingThis { get; set; }
56+
}
57+
58+
public class WordType
59+
{
60+
public required bool Function { get; set; }
61+
public required bool Class { get; set; }
62+
public required bool CodeNote { get; set; }
63+
}
64+
}

0 commit comments

Comments
 (0)