Skip to content

Commit ea5780b

Browse files
committed
Fixes #338
1 parent 9ab85c3 commit ea5780b

File tree

5 files changed

+133
-100
lines changed

5 files changed

+133
-100
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
## [2.5.2] - 2024-XX-XX
44
- Fix issue [#336](https://github.com/intersystems/language-server/issues/336): Add intellisense for variables set to the returned value of a method, or a property, with a declared type
55
- Fix issue [#337](https://github.com/intersystems/language-server/issues/337): Improve Hover headers
6+
- Fix issue [#338](https://github.com/intersystems/language-server/issues/338): Add intellisense for macros in Embedded SQL
67

78
## [2.5.1] - 2024-07-09
89
- Fix issue [#328](https://github.com/intersystems/language-server/issues/328): Fix namespace detection for Diagnostic computation

server/src/providers/completion.ts

+33-33
Original file line numberDiff line numberDiff line change
@@ -706,15 +706,15 @@ export async function onCompletion(params: CompletionParams): Promise<Completion
706706
}
707707
const settings = await getLanguageServerSettings(params.textDocument.uri);
708708

709-
if (prevline.slice(-3) === "$$$" && triggerlang === ld.cos_langindex) {
709+
if (prevline.slice(-3) == "$$$" && [ld.cos_langindex,ld.sql_langindex].includes(triggerlang)) {
710710
// This is a macro
711711

712712
// Get the details of this class and store them in the cache
713-
var maccon = getMacroContext(doc,parsed,params.position.line);
713+
const maccon = getMacroContext(doc,parsed,params.position.line,triggerlang == ld.sql_langindex);
714714
macroCompletionCache = maccon;
715715

716716
// Get the entire macro list from the server
717-
var cursorisopen: boolean = true;
717+
let cursorisopen: boolean = true;
718718
while (cursorisopen) {
719719
const respdata = await makeRESTRequest("POST",2,"/action/getmacrolist",server,maccon);
720720
if (respdata !== undefined && respdata.data.result.content.macros.length > 0) {
@@ -766,13 +766,13 @@ export async function onCompletion(params: CompletionParams): Promise<Completion
766766
if (parsed[ln][0].l == ld.cos_langindex && parsed[ln][0].s == ld.cos_ppc_attrindex) {
767767
// This line begins with a preprocessor command
768768
const ppctext = doc.getText(Range.create(
769-
Position.create(ln,parsed[ln][1].p),
770-
Position.create(ln,parsed[ln][1].p+parsed[ln][1].c)
769+
ln,parsed[ln][1].p,
770+
ln,parsed[ln][1].p+parsed[ln][1].c
771771
)).toLowerCase();
772-
if (ppctext === "define" || ppctext === "def1arg") {
772+
if (ppctext == "define" || ppctext == "def1arg") {
773773
// This is a macro definition
774-
var macrodef: CompletionItem = {
775-
label: doc.getText(Range.create(Position.create(ln,parsed[ln][2].p),Position.create(ln,parsed[ln][2].p+parsed[ln][2].c))),
774+
const macrodef: CompletionItem = {
775+
label: doc.getText(Range.create(ln,parsed[ln][2].p,ln,parsed[ln][2].p+parsed[ln][2].c)),
776776
kind: CompletionItemKind.Text,
777777
data: ["macro",doc.uri]
778778
};
@@ -781,54 +781,54 @@ export async function onCompletion(params: CompletionParams): Promise<Completion
781781
if (
782782
parsed[ln][parsed[ln].length-1].l === ld.cos_langindex && parsed[ln][parsed[ln].length-1].s === ld.cos_ppf_attrindex &&
783783
doc.getText(Range.create(
784-
Position.create(ln,parsed[ln][parsed[ln].length-1].p),
785-
Position.create(ln,parsed[ln][parsed[ln].length-1].p+parsed[ln][parsed[ln].length-1].c)
786-
)).toLowerCase() === "continue"
784+
ln,parsed[ln][parsed[ln].length-1].p,
785+
ln,parsed[ln][parsed[ln].length-1].p+parsed[ln][parsed[ln].length-1].c
786+
)).toLowerCase() == "continue"
787787
) {
788788
// This is the start of a multi-line macro definition
789789
const restofline = doc.getText(Range.create(
790-
Position.create(ln,parsed[ln][3].p),
791-
Position.create(ln,parsed[ln][parsed[ln].length-1].p+parsed[ln][parsed[ln].length-1].c)
790+
ln,parsed[ln][3].p,
791+
ln,parsed[ln][parsed[ln].length-1].p+parsed[ln][parsed[ln].length-1].c
792792
));
793-
var docstr = macrodef.label;
793+
let docstr = macrodef.label;
794794
if (parsed[ln][3].l == ld.cos_langindex && parsed[ln][3].s == ld.cos_delim_attrindex) {
795795
// This macro has args
796-
var argsmatchres = restofline.match(argsregex);
797-
if (argsmatchres !== null) {
796+
const argsmatchres = restofline.match(argsregex);
797+
if (argsmatchres != null) {
798798
docstr = docstr + argsmatchres[1];
799799
}
800800
}
801801

802-
var flvalmatchres = restofline.match(/^(?:\([^\(\)]+\) *){0,1}(.*)( *##continue)$/i);
803-
if (flvalmatchres !== null) {
804-
if (flvalmatchres[1] !== "") {
802+
const flvalmatchres = restofline.match(/^(?:\([^\(\)]+\) *){0,1}(.*)( *##continue)$/i);
803+
if (flvalmatchres != null) {
804+
if (flvalmatchres[1] != "") {
805805
docstr = docstr + "\n" + flvalmatchres[1].trim();
806806
}
807807
for (let mln = ln+1; mln < parsed.length; mln++) {
808808
if (
809-
parsed[mln][parsed[mln].length-1].l === ld.cos_langindex && parsed[mln][parsed[mln].length-1].s === ld.cos_ppf_attrindex &&
809+
parsed[mln][parsed[mln].length-1].l == ld.cos_langindex && parsed[mln][parsed[mln].length-1].s == ld.cos_ppf_attrindex &&
810810
doc.getText(Range.create(
811-
Position.create(mln,parsed[mln][parsed[mln].length-1].p),
812-
Position.create(mln,parsed[mln][parsed[mln].length-1].p+parsed[mln][parsed[mln].length-1].c)
813-
)).toLowerCase() === "continue"
811+
mln,parsed[mln][parsed[mln].length-1].p,
812+
mln,parsed[mln][parsed[mln].length-1].p+parsed[mln][parsed[mln].length-1].c
813+
)).toLowerCase() == "continue"
814814
) {
815815
// This is a line of the multi-line macro definition
816816
docstr = docstr + "\n" + doc.getText(Range.create(
817-
Position.create(mln,parsed[mln][0].p),
818-
Position.create(mln,parsed[mln][parsed[mln].length-3].p+parsed[mln][parsed[mln].length-3].c)
817+
mln,parsed[mln][0].p,
818+
mln,parsed[mln][parsed[mln].length-3].p+parsed[mln][parsed[mln].length-3].c
819819
));
820820
}
821821
else {
822822
// This is the last line of the multi-line macro definition
823823
docstr = docstr + "\n" + doc.getText(Range.create(
824-
Position.create(mln,parsed[mln][0].p),
825-
Position.create(mln,parsed[mln][parsed[mln].length-1].p+parsed[mln][parsed[mln].length-1].c)
824+
mln,parsed[mln][0].p,
825+
mln,parsed[mln][parsed[mln].length-1].p+parsed[mln][parsed[mln].length-1].c
826826
));
827827
break;
828828
}
829829
}
830830
}
831-
if (docstr !== macrodef.label) {
831+
if (docstr != macrodef.label) {
832832
macrodef.documentation = {
833833
kind: "plaintext",
834834
value: docstr
@@ -838,18 +838,18 @@ export async function onCompletion(params: CompletionParams): Promise<Completion
838838
else {
839839
// This is a single line macro definition
840840
const restofline = doc.getText(Range.create(
841-
Position.create(ln,parsed[ln][3].p),
842-
Position.create(ln,parsed[ln][parsed[ln].length-1].p+parsed[ln][parsed[ln].length-1].c)
841+
ln,parsed[ln][3].p,
842+
ln,parsed[ln][parsed[ln].length-1].p+parsed[ln][parsed[ln].length-1].c
843843
));
844-
var docstr = macrodef.label;
844+
let docstr = macrodef.label;
845845
if (parsed[ln][3].l == ld.cos_langindex && parsed[ln][3].s == ld.cos_delim_attrindex) {
846846
// This macro has args
847-
var argsmatchres = restofline.match(argsregex);
847+
const argsmatchres = restofline.match(argsregex);
848848
if (argsmatchres !== null) {
849849
docstr = docstr + argsmatchres[1];
850850
}
851851
}
852-
var valmatchres = restofline.match(valregex);
852+
const valmatchres = restofline.match(valregex);
853853
if (valmatchres !== null) {
854854
macrodef.documentation = {
855855
kind: "plaintext",

server/src/providers/definition.ts

+25-13
Original file line numberDiff line numberDiff line change
@@ -154,16 +154,28 @@ export async function onDefinition(params: TextDocumentPositionParams) {
154154
}
155155
}
156156
}
157-
else if (parsed[params.position.line][i].l == ld.cos_langindex && parsed[params.position.line][i].s == ld.cos_macro_attrindex) {
157+
else if (
158+
parsed[params.position.line][i].l == ld.cos_langindex && parsed[params.position.line][i].s == ld.cos_macro_attrindex || (
159+
parsed[params.position.line][i].l == ld.sql_langindex &&
160+
parsed[params.position.line][i].s == ld.sql_iden_attrindex &&
161+
doc.getText(Range.create(params.position.line,symbolstart,params.position.line,symbolstart+3)) == "$$$"
162+
)
163+
) {
158164
// This is a macro
159165

160166
// Get the details of this class
161-
const maccon = getMacroContext(doc,parsed,params.position.line);
167+
const isSql = parsed[params.position.line][i].l == ld.sql_langindex;
168+
const maccon = getMacroContext(doc,parsed,params.position.line,isSql);
162169

163170
// Get the full range of the macro
164171
const macrorange = findFullRange(params.position.line,parsed,i,symbolstart,symbolend);
165-
var macrotext = doc.getText(macrorange);
166-
if (macrotext.slice(0,3) === "$$$") {
172+
let macrotext = doc.getText(macrorange);
173+
if (isSql && macrotext.includes("(")) {
174+
// SQL macros with arguments have the arguments as part of the same token
175+
macrotext = macrotext.slice(0, macrotext.indexOf("("));
176+
macrorange.end = Position.create(params.position.line, symbolstart + macrotext.length);
177+
}
178+
if (macrotext.slice(0,3) == "$$$") {
167179
macrotext = macrotext.slice(3);
168180
}
169181

@@ -173,21 +185,21 @@ export async function onDefinition(params: TextDocumentPositionParams) {
173185
if (macrodefline !== -1) {
174186
// The macro definition is in the current file
175187

176-
var targetrange = Range.create(Position.create(macrodefline,0),Position.create(macrodefline+1,0));
188+
const targetrange = Range.create(macrodefline,0,macrodefline+1,0);
177189
if (
178-
parsed[macrodefline][parsed[macrodefline].length-1].l === ld.cos_langindex && parsed[macrodefline][parsed[macrodefline].length-1].s === ld.cos_ppf_attrindex &&
190+
parsed[macrodefline][parsed[macrodefline].length-1].l == ld.cos_langindex && parsed[macrodefline][parsed[macrodefline].length-1].s == ld.cos_ppf_attrindex &&
179191
doc.getText(Range.create(
180-
Position.create(macrodefline,parsed[macrodefline][parsed[macrodefline].length-1].p),
181-
Position.create(macrodefline,parsed[macrodefline][parsed[macrodefline].length-1].p+parsed[macrodefline][parsed[macrodefline].length-1].c)
192+
macrodefline,parsed[macrodefline][parsed[macrodefline].length-1].p,
193+
macrodefline,parsed[macrodefline][parsed[macrodefline].length-1].p+parsed[macrodefline][parsed[macrodefline].length-1].c
182194
)).toLowerCase() === "continue"
183195
) {
184196
// This is a multi-line macro definition so scan down the file to capture the full range of the definition
185197
for (let mln = macrodefline+1; mln < parsed.length; mln++) {
186198
if (
187199
parsed[mln][parsed[mln].length-1].l !== ld.cos_langindex || parsed[mln][parsed[mln].length-1].s !== ld.cos_ppf_attrindex ||
188200
doc.getText(Range.create(
189-
Position.create(mln,parsed[mln][parsed[mln].length-1].p),
190-
Position.create(mln,parsed[mln][parsed[mln].length-1].p+parsed[mln][parsed[mln].length-1].c)
201+
mln,parsed[mln][parsed[mln].length-1].p,
202+
mln,parsed[mln][parsed[mln].length-1].p+parsed[mln][parsed[mln].length-1].c
191203
)).toLowerCase() !== "continue"
192204
) {
193205
// This is the last line of the macro definition so update the target range
@@ -201,7 +213,7 @@ export async function onDefinition(params: TextDocumentPositionParams) {
201213
targetUri: params.textDocument.uri,
202214
targetRange: targetrange,
203215
originSelectionRange: macrorange,
204-
targetSelectionRange: Range.create(Position.create(macrodefline,parsed[macrodefline][2].p),Position.create(macrodefline,parsed[macrodefline][2].p+parsed[macrodefline][2].c))
216+
targetSelectionRange: Range.create(macrodefline,parsed[macrodefline][2].p,macrodefline,parsed[macrodefline][2].p+parsed[macrodefline][2].c)
205217
}];
206218
}
207219
else {
@@ -227,9 +239,9 @@ export async function onDefinition(params: TextDocumentPositionParams) {
227239
if (newuri !== "") {
228240
return [{
229241
targetUri: newuri,
230-
targetRange: Range.create(Position.create(respdata.data.result.content.line,0),Position.create(respdata.data.result.content.line+1,0)),
242+
targetRange: Range.create(respdata.data.result.content.line,0,respdata.data.result.content.line+1,0),
231243
originSelectionRange: macrorange,
232-
targetSelectionRange: Range.create(Position.create(respdata.data.result.content.line,0),Position.create(respdata.data.result.content.line+1,0))
244+
targetSelectionRange: Range.create(respdata.data.result.content.line,0,respdata.data.result.content.line+1,0)
233245
}];
234246
}
235247
}

server/src/providers/hover.ts

+21-5
Original file line numberDiff line numberDiff line change
@@ -105,21 +105,37 @@ export async function onHover(params: TextDocumentPositionParams): Promise<Hover
105105
};
106106
}
107107
}
108-
else if (parsed[params.position.line][i].l == ld.cos_langindex && parsed[params.position.line][i].s == ld.cos_macro_attrindex) {
108+
else if (
109+
parsed[params.position.line][i].l == ld.cos_langindex && parsed[params.position.line][i].s == ld.cos_macro_attrindex || (
110+
parsed[params.position.line][i].l == ld.sql_langindex &&
111+
parsed[params.position.line][i].s == ld.sql_iden_attrindex &&
112+
doc.getText(Range.create(params.position.line,symbolstart,params.position.line,symbolstart+3)) == "$$$"
113+
)
114+
) {
109115
// This is a macro
110116

111117
// Get the details of this class
112-
const maccon = getMacroContext(doc,parsed,params.position.line);
118+
const isSql = parsed[params.position.line][i].l == ld.sql_langindex;
119+
const maccon = getMacroContext(doc,parsed,params.position.line,isSql);
113120

114121
// Get the full range of the macro
115122
const macrorange = findFullRange(params.position.line,parsed,i,symbolstart,symbolend);
116-
var macrotext = doc.getText(macrorange);
117-
if (macrotext.slice(0,3) === "$$$") {
123+
let macrotext = doc.getText(macrorange);
124+
let sqlMacroArgs = "";
125+
if (isSql && macrotext.includes("(")) {
126+
// SQL macros with arguments have the arguments as part of the same token
127+
const parenIdx = macrotext.indexOf("(");
128+
sqlMacroArgs = macrotext.slice(parenIdx).replace(/\s+/g,"");
129+
macrotext = macrotext.slice(0, parenIdx);
130+
macrorange.end = Position.create(params.position.line, symbolstart + macrotext.length);
131+
}
132+
if (macrotext.slice(0,3) == "$$$") {
118133
macrotext = macrotext.slice(3);
119134
}
120135

121136
/** Helper function for getting the arguments passed to this macro. */
122137
const getMacroArgs = (): string => {
138+
if (isSql) return sqlMacroArgs;
123139
// Get the rest of the line following the macro
124140
const restofline = doc.getText(Range.create(
125141
params.position.line,macrorange.end.character,
@@ -145,7 +161,7 @@ export async function onHover(params: TextDocumentPositionParams): Promise<Hover
145161
}
146162
if (closeidx !== -1) {
147163
// Get all of the arguments
148-
macroargs = restofline.slice(0,closeidx+1).replace(" ","");
164+
macroargs = restofline.slice(0,closeidx+1).replace(/\s+/g,"");
149165
}
150166
else {
151167
// The argument list is incomplete

0 commit comments

Comments
 (0)