diff --git a/extension/client/src/editor.ts b/extension/client/src/editor.ts new file mode 100644 index 00000000..ea5bcdfa --- /dev/null +++ b/extension/client/src/editor.ts @@ -0,0 +1,70 @@ +import { ExtensionContext, Range, SnippetString, TextDocument, commands, window } from "vscode"; + +export function initialise(context: ExtensionContext) { + context.subscriptions.push( + commands.registerCommand("vscode-rpgle.surroundWithMonitor", () => surroundWithSnippet(lines => [ + "", + "monitor;", + ...lines, + "on-excp '$1';", + "on-error$2;", + "endmon;", + "" + ])) + ); +} + +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 (isFree(document.lineAt(line).text, isFullyFree)) { + // First let's find out if this line starts elsewhere + 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 + 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(';') || isFreeLineEnd(text, isFullyFree))) { + break; + } + } + + editor.insertSnippet(new SnippetString(snippetProvider(lines).join("\n")), + new Range(startLine, document.lineAt(startLine).firstNonWhitespaceCharacterIndex, line - 1, 9999)); + } else { + window.showWarningMessage("Selection is not valid Free RPGLE code"); + } + } +} + +function isFullyFreeRPGLE(document: TextDocument) { + if (document.lineAt(0).text.substring(0, 6).toLowerCase() === `**free`) { + return true; + } + else { + 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 diff --git a/extension/client/src/extension.ts b/extension/client/src/extension.ts index dffcf252..09b48491 100644 --- a/extension/client/src/extension.ts +++ b/extension/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 2340a6d2..54106c1b 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" + } ] } }, @@ -104,4 +137,4 @@ "webpack": "^5.76.0", "webpack-cli": "^4.5.0" } -} +} \ No newline at end of file