From ee3b7e559c669d82da524540d8b2fde9bbd169b0 Mon Sep 17 00:00:00 2001 From: Seb Julliand Date: Wed, 7 Jun 2023 22:29:35 +0200 Subject: [PATCH 1/3] Added RPGLE menu + Surround with monitor action --- client/src/editor.ts | 65 +++++++++++++++++++++++++++++++++++++++++ client/src/extension.ts | 7 +++-- package.json | 37 +++++++++++++++++++++-- 3 files changed, 104 insertions(+), 5 deletions(-) create mode 100644 client/src/editor.ts diff --git a/client/src/editor.ts b/client/src/editor.ts new file mode 100644 index 00000000..124888cd --- /dev/null +++ b/client/src/editor.ts @@ -0,0 +1,65 @@ +import { ExtensionContext, Range, SnippetString, TextDocument, commands, window } from "vscode"; + +export function initialise(context: ExtensionContext) { + context.subscriptions.push( + commands.registerCommand("vscode-rpgle.surroundWithMonitor", surroundWithMonitor) + ); +} + +function surroundWithMonitor() { + const editor = window.activeTextEditor; + if (editor) { + const document = editor.document; + let line = editor.selection.start.line; + if (isFreeRPGLE(document, line)) { + // First let's find out if this line starts elsewhere + while ((line - 1) >= 0 && !document.lineAt(line).text.trim().endsWith(`;`) && line-- > 0); + const startLine = line; + + // Now get all the relevant lines + const lines: string[] = []; + let initialIdentation = document.lineAt(line).firstNonWhitespaceCharacterIndex; + while (line < document.lineCount) { + const currentLine = document.lineAt(line++); + const text = currentLine.text; + //Keep identation + const indent = currentLine.firstNonWhitespaceCharacterIndex - initialIdentation; + lines.push(`${"".padEnd(2 + (indent > 0 ? indent : 0))}${text.trim()}`); + const maybeComment = text.lastIndexOf("//"); + if (line > editor.selection.end.line && (maybeComment > -1 ? text.substring(maybeComment + 1) : text).endsWith(';')) { + break; + } + } + + editor.insertSnippet(new SnippetString([ + "", + "monitor;", + ...lines, + "on-excp '$1';", + "on-error$2;", + "endmon;", + "" + ].join("\n")), new Range(startLine, document.lineAt(startLine).firstNonWhitespaceCharacterIndex, line-1, 9999)); + } + else{ + window.showWarningMessage("Selection is not valid Free RPGLE code"); + } + } +} + +function isFreeRPGLE(document: TextDocument, currentLine: number) { + if (document.lineAt(0).text.substring(0, 6).toLowerCase() === `**free`) { + return true; + } + else { + for (let i = currentLine; i < document.lineCount; i++) { + const line = document.lineAt(i).text; + if (line.length > 10 && line.substring(6, 11).toLowerCase() === '/free') { + return false; + } + else if (line.length > 14 && line.substring(6, 15).toLowerCase() === '/end-free') { + return true; + } + } + } +} diff --git a/client/src/extension.ts b/client/src/extension.ts index dffcf252..09b48491 100644 --- a/client/src/extension.ts +++ b/client/src/extension.ts @@ -4,10 +4,10 @@ * ------------------------------------------------------------------------------------------ */ import * as path from 'path'; -import { workspace, ExtensionContext, Uri, commands, RelativePattern } from 'vscode'; +import { ExtensionContext, workspace } from 'vscode'; -import * as Linter from "./linter"; import * as columnAssist from "./columnAssist"; +import * as Linter from "./linter"; import { @@ -18,6 +18,7 @@ import { } from 'vscode-languageclient/node'; import { projectFilesGlob } from './configuration'; +import { initialise as initialiseEditorCommands } from './editor'; import buildRequestHandlers from './requests'; let client: LanguageClient; @@ -74,7 +75,7 @@ export function activate(context: ExtensionContext) { Linter.initialise(context); columnAssist.registerColumnAssist(context); - + initialiseEditorCommands(context); // context.subscriptions.push(...initBuilder(client)); console.log(`started`); diff --git a/package.json b/package.json index b16ffd43..1953eb6a 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,11 @@ "vscode": "^1.70.0" }, "keywords": [ - "rpg", "rpgle", "ibmi", "iseries", "as400" + "rpg", + "rpgle", + "ibmi", + "iseries", + "as400" ], "categories": [ "Programming Languages", @@ -58,15 +62,44 @@ "command": "vscode-rpgle.openLintConfig", "title": "Open RPGLE lint configuration", "category": "RPGLE" + }, + { + "command": "vscode-rpgle.surroundWithMonitor", + "title": "Surround with monitor", + "category": "RPGLE" + } + ], + "submenus": [ + { + "id": "vscode-rpgle.editor.menu", + "label": "RPGLE" } ], "menus": { + "vscode-rpgle.editor.menu": [ + { + "command": "vscode-rpgle.surroundWithMonitor" + } + ], + "commandPalette": [ + { + "command": "vscode-rpgle.surroundWithMonitor", + "when": "editorLangId === rpgle" + } + ], "view/item/context": [ { "command": "vscode-rpgle.openLintConfig", "when": "view == objectBrowser && viewItem == filter", "group": "1_LibActions@2" } + ], + "editor/context": [ + { + "submenu": "vscode-rpgle.editor.menu", + "when": "editorLangId === rpgle", + "group": "01_rpgleActions@01" + } ] } }, @@ -103,4 +136,4 @@ "webpack": "^5.24.3", "webpack-cli": "^4.5.0" } -} +} \ No newline at end of file From d7688496bea39d6024bfcb99819f72ebd88d1478 Mon Sep 17 00:00:00 2001 From: Seb Julliand Date: Wed, 7 Jun 2023 22:37:19 +0200 Subject: [PATCH 2/3] Extracted function for eventual future snippets --- client/src/editor.ts | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/client/src/editor.ts b/client/src/editor.ts index 124888cd..c42361c3 100644 --- a/client/src/editor.ts +++ b/client/src/editor.ts @@ -2,11 +2,19 @@ import { ExtensionContext, Range, SnippetString, TextDocument, commands, window export function initialise(context: ExtensionContext) { context.subscriptions.push( - commands.registerCommand("vscode-rpgle.surroundWithMonitor", surroundWithMonitor) + commands.registerCommand("vscode-rpgle.surroundWithMonitor", () => surroundWithSnippet(lines => [ + "", + "monitor;", + ...lines, + "on-excp '$1';", + "on-error$2;", + "endmon;", + "" + ])) ); } -function surroundWithMonitor() { +function surroundWithSnippet(snippetProvider: (lines: string[]) => string[]) { const editor = window.activeTextEditor; if (editor) { const document = editor.document; @@ -31,17 +39,10 @@ function surroundWithMonitor() { } } - editor.insertSnippet(new SnippetString([ - "", - "monitor;", - ...lines, - "on-excp '$1';", - "on-error$2;", - "endmon;", - "" - ].join("\n")), new Range(startLine, document.lineAt(startLine).firstNonWhitespaceCharacterIndex, line-1, 9999)); + editor.insertSnippet(new SnippetString(snippetProvider(lines).join("\n")), + new Range(startLine, document.lineAt(startLine).firstNonWhitespaceCharacterIndex, line - 1, 9999)); } - else{ + else { window.showWarningMessage("Selection is not valid Free RPGLE code"); } } From 529ad25800ee79ec64024f73500e81dcafa7b43a Mon Sep 17 00:00:00 2001 From: Seb Julliand Date: Mon, 26 Jun 2023 14:31:00 +0200 Subject: [PATCH 3/3] Don't detect free with /free + fixed full line detection --- extension/client/src/editor.ts | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/extension/client/src/editor.ts b/extension/client/src/editor.ts index c42361c3..ea5bcdfa 100644 --- a/extension/client/src/editor.ts +++ b/extension/client/src/editor.ts @@ -18,10 +18,13 @@ function surroundWithSnippet(snippetProvider: (lines: string[]) => string[]) { const editor = window.activeTextEditor; if (editor) { const document = editor.document; + const isFullyFree = isFullyFreeRPGLE(document); let line = editor.selection.start.line; - if (isFreeRPGLE(document, line)) { + if (isFree(document.lineAt(line).text, isFullyFree)) { // First let's find out if this line starts elsewhere - while ((line - 1) >= 0 && !document.lineAt(line).text.trim().endsWith(`;`) && line-- > 0); + if (!isFreeLineEnd(document.lineAt(line).text, isFullyFree)) { + while ((line - 1) >= 0 && !isFreeLineEnd(document.lineAt(line - 1).text, isFullyFree) && line-- > 0); + } const startLine = line; // Now get all the relevant lines @@ -34,33 +37,34 @@ function surroundWithSnippet(snippetProvider: (lines: string[]) => string[]) { const indent = currentLine.firstNonWhitespaceCharacterIndex - initialIdentation; lines.push(`${"".padEnd(2 + (indent > 0 ? indent : 0))}${text.trim()}`); const maybeComment = text.lastIndexOf("//"); - if (line > editor.selection.end.line && (maybeComment > -1 ? text.substring(maybeComment + 1) : text).endsWith(';')) { + if (line > editor.selection.end.line && ((maybeComment > -1 ? text.substring(maybeComment + 1) : text).endsWith(';') || isFreeLineEnd(text, isFullyFree))) { break; } } editor.insertSnippet(new SnippetString(snippetProvider(lines).join("\n")), new Range(startLine, document.lineAt(startLine).firstNonWhitespaceCharacterIndex, line - 1, 9999)); - } - else { + } else { window.showWarningMessage("Selection is not valid Free RPGLE code"); } } } -function isFreeRPGLE(document: TextDocument, currentLine: number) { +function isFullyFreeRPGLE(document: TextDocument) { if (document.lineAt(0).text.substring(0, 6).toLowerCase() === `**free`) { return true; } else { - for (let i = currentLine; i < document.lineCount; i++) { - const line = document.lineAt(i).text; - if (line.length > 10 && line.substring(6, 11).toLowerCase() === '/free') { - return false; - } - else if (line.length > 14 && line.substring(6, 15).toLowerCase() === '/end-free') { - return true; - } - } + return false; } } + +function isFreeLineEnd(line: string, free: boolean) { + const endPos = line.lastIndexOf(';'); + const commentPos = line.lastIndexOf('//'); + return !isFree(line, free) || line.trim().endsWith(`;`) || (endPos > -1 && commentPos > endPos); +} + +function isFree(line: string, free: boolean) { + return free || !(['H', 'F', 'D', 'I', 'C', 'O', 'P'].includes(line.charAt(5).toUpperCase()) || ['/', '*'].includes(line.charAt(6))); +} \ No newline at end of file