Skip to content

Commit 75dd815

Browse files
authored
Merge pull request #378 from codefori/feature/monitor_code_action
Monitor code action
2 parents 6959715 + 956389a commit 75dd815

File tree

4 files changed

+124
-14
lines changed

4 files changed

+124
-14
lines changed

extension/server/src/data.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,8 @@ export function dspffdToRecordFormats(data: any, aliases = false): Declaration[]
5858
field: ``,
5959
pos: ``
6060
});
61-
62-
currentSubfield.tags.push({tag: `description`, content: text.trim()})
61+
62+
currentSubfield.tags.push({tag: `description`, content: text.trim()});
6363

6464
recordFormat.subItems.push(currentSubfield);
6565
});

extension/server/src/providers/codeActions.ts

Lines changed: 119 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ export default async function genericCodeActionsProvider(params: CodeActionParam
2424

2525
const extractOption = getExtractProcedureAction(document, docs, range);
2626
if (extractOption) {
27-
return [extractOption];
27+
actions.push(extractOption);
2828
}
2929

3030
const linterActions = await getLinterCodeActions(docs, document, range);
@@ -37,6 +37,11 @@ export default async function genericCodeActionsProvider(params: CodeActionParam
3737
// if (testCaseOption) {
3838
// actions.push(testCaseOption);
3939
// }
40+
41+
const monitorAction = surroundWithMonitorAction(isFree, document, docs, range);
42+
if (monitorAction) {
43+
actions.push(monitorAction);
44+
}
4045
}
4146
}
4247

@@ -71,7 +76,102 @@ export function getTestCaseAction(document: TextDocument, docs: Cache, range: Ra
7176
}
7277
}
7378

74-
export function getSubroutineActions(document: TextDocument, docs: Cache, range: Range): CodeAction|undefined {
79+
function lineAt(document: TextDocument, line: number): string {
80+
return document.getText(Range.create(line, 0, line, 1000)).trimEnd();
81+
}
82+
83+
function getBodyRangeForRange(docs: Cache, rangeStart: number, rangeEnd: number, document: TextDocument) {
84+
let validStart = -1;
85+
let validEnd = -1;
86+
87+
const currentProcedure = docs.procedures.find(sub => rangeStart >= sub.position.range.line && rangeEnd <= sub.range.end!);
88+
89+
if (currentProcedure && currentProcedure.scope && currentProcedure.range.end) {
90+
validStart = currentProcedure.scope.getDefinitionBlockEnd(document.uri) + 1;
91+
validEnd = currentProcedure.range.end - 1;
92+
} else {
93+
validStart = docs.getDefinitionBlockEnd(document.uri) + 1;
94+
const firstProc = docs.procedures.find(p => !Object.keys(p.keyword).some(k => k.toLowerCase().startsWith(`ext`)));
95+
validEnd = firstProc && firstProc.range.start ? firstProc.range.start - 1 : document.lineCount - 1;
96+
}
97+
98+
if (validStart < 0 || validEnd < 0) {
99+
return;
100+
}
101+
102+
return { validStart, validEnd };
103+
}
104+
105+
function determineIndent(line: string): number {
106+
const match = line.match(/^\s+/);
107+
if (match) {
108+
return match[0].length;
109+
}
110+
return 0;
111+
}
112+
113+
export function surroundWithMonitorAction(isFree: boolean, document: TextDocument, docs: Cache, range: Range): CodeAction | undefined {
114+
let rangeStart = range.start.line;
115+
let rangeEnd = range.end.line;
116+
117+
if (rangeStart === rangeEnd) {
118+
// Only works for multi-line selections
119+
return;
120+
}
121+
122+
const validRange = getBodyRangeForRange(docs, rangeStart, rangeEnd, document);
123+
124+
if (!validRange) {
125+
return;
126+
}
127+
128+
let indent = 0;
129+
130+
if (isFree) {
131+
indent = determineIndent(lineAt(document, rangeStart));
132+
} else {
133+
const freePortion = lineAt(document, rangeStart).substring(7);
134+
indent = determineIndent(freePortion) + 7;
135+
}
136+
137+
const newLine = `\n`;
138+
const indentStr = ` `.repeat(indent);
139+
const space = `${newLine}${indentStr}`;
140+
141+
if (rangeStart >= validRange.validStart && rangeEnd <= validRange.validEnd) {
142+
const refactorAction = CodeAction.create(`Surround with monitor`, CodeActionKind.RefactorRewrite);
143+
144+
refactorAction.edit = {
145+
changes: {
146+
[document.uri]: [
147+
TextEdit.insert(
148+
Position.create(rangeStart, 0),
149+
`${indentStr}monitor;${newLine}`
150+
),
151+
TextEdit.insert(
152+
Position.create(rangeEnd + 1, 0),
153+
`${space}on-error *all;${space} // TODO: implement${space}endmon;${newLine}`
154+
)
155+
]
156+
},
157+
};
158+
159+
if (isFree) {
160+
// Then format the document
161+
refactorAction.command = {
162+
command: `editor.action.formatDocument`,
163+
title: `Format`
164+
};
165+
}
166+
167+
return refactorAction;
168+
}
169+
170+
171+
return;
172+
}
173+
174+
export function getSubroutineActions(document: TextDocument, docs: Cache, range: Range): CodeAction | undefined {
75175
if (range.start.line === range.end.line) {
76176
const currentGlobalSubroutine = docs.subroutines.find(sub => sub.position.range.line === range.start.line && sub.range.start && sub.range.end);
77177

@@ -93,7 +193,7 @@ export function getSubroutineActions(document: TextDocument, docs: Cache, range:
93193
const newProcedure = [
94194
`Dcl-Proc ${currentGlobalSubroutine.name};`,
95195
` Dcl-Pi *N;`,
96-
...extracted.references.map((ref, i) => ` ${extracted.newParamNames[i]} ${ref.dec.type === `struct` ? `LikeDS` : `Like`}(${ref.dec.name});`),
196+
...extracted.references.map((ref, i) => ` ${extracted.newParamNames[i]} ${ref.dec.type === `struct` ? `LikeDS` : `Like`}(${ref.dec.name});`),
97197
` End-Pi;`,
98198
``,
99199
caseInsensitiveReplaceAll(extracted.newBody, `leavesr`, `return`),
@@ -131,30 +231,40 @@ export function getSubroutineActions(document: TextDocument, docs: Cache, range:
131231
}
132232
}
133233

134-
export function getExtractProcedureAction(document: TextDocument, docs: Cache, range: Range): CodeAction|undefined {
135-
if (range.end.line > range.start.line) {
136-
const lastLine = document.offsetAt({line: document.lineCount, character: 0});
234+
export function getExtractProcedureAction(document: TextDocument, docs: Cache, range: Range): CodeAction | undefined {
235+
const rangeStart = range.start.line;
236+
const rangeEnd = range.end.line;
237+
if (rangeEnd > rangeStart) {
238+
239+
const validRange = getBodyRangeForRange(docs, rangeStart, rangeEnd, document);
137240

241+
if (!validRange) {
242+
return;
243+
}
244+
245+
// Ensure the selected range is within a body range
246+
if (rangeStart >= validRange.validStart && rangeEnd <= validRange.validEnd) {
138247
const extracted = createExtract(document, range, docs);
139248

140249
const newProcedure = [
141250
`Dcl-Proc NewProcedure;`,
142251
` Dcl-Pi *N;`,
143-
...extracted.references.map((ref, i) => ` ${extracted.newParamNames[i]} ${ref.dec.type === `struct` ? `LikeDS` : `Like`}(${ref.dec.name});`),
252+
...extracted.references.map((ref, i) => ` ${extracted.newParamNames[i]} ${ref.dec.type === `struct` ? `LikeDS` : `Like`}(${ref.dec.name});`),
144253
` End-Pi;`,
145254
``,
146255
extracted.newBody,
147256
`End-Proc;`
148257
].join(`\n`)
149258

150259
const newAction = CodeAction.create(`Extract to new procedure`, CodeActionKind.RefactorExtract);
260+
const lastLine = document.offsetAt({ line: document.lineCount, character: 0 });
151261

152262
// First do the exit
153263
newAction.edit = {
154264
changes: {
155265
[document.uri]: [
156266
TextEdit.replace(extracted.range, `NewProcedure(${extracted.references.map(r => r.dec.name).join(`:`)});`),
157-
TextEdit.insert(document.positionAt(lastLine), `\n\n`+newProcedure)
267+
TextEdit.insert(document.positionAt(lastLine), `\n\n` + newProcedure)
158268
]
159269
},
160270
};
@@ -166,5 +276,6 @@ export function getExtractProcedureAction(document: TextDocument, docs: Cache, r
166276
};
167277

168278
return newAction;
279+
}
169280
}
170281
}

extension/server/src/providers/linter/codeActions.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
1-
import { CodeAction, CodeActionKind, CodeActionParams, Range } from 'vscode-languageserver';
2-
import { getActions, getExtractProcedureAction, getSubroutineActions, refreshLinterDiagnostics } from '.';
3-
import { documents, parser } from '..';
1+
import { Range } from 'vscode-languageserver';
2+
import { getActions, refreshLinterDiagnostics } from '.';
43
import { TextDocument } from 'vscode-languageserver-textdocument';
54
import Cache from '../../../../../language/models/cache';
65

language/models/cache.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ export default class Cache {
8686
* @param {string} fsPath Path to check
8787
* @returns {number} Line number
8888
*/
89-
getDefinitionBlockEnd(fsPath) {
89+
getDefinitionBlockEnd(fsPath: string) {
9090
const lasts = [
9191
this.procedures.filter(d => d.position.path === fsPath && d.keyword[`EXTPROC`] !== undefined).pop(),
9292
this.structs.filter(d => d.position.path === fsPath).pop(),

0 commit comments

Comments
 (0)