From 16538261f6c49dacdf849ef1bfd85bb17fb7a768 Mon Sep 17 00:00:00 2001 From: Sante Barbuto Date: Wed, 8 Nov 2023 17:37:32 +0100 Subject: [PATCH 1/7] chore: Renamed function in codeActionProvider --- src/codeActionProvider.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/codeActionProvider.ts b/src/codeActionProvider.ts index 3d2f116..1662fc0 100644 --- a/src/codeActionProvider.ts +++ b/src/codeActionProvider.ts @@ -180,7 +180,7 @@ export default class CodeActionProvider implements VSCodeCodeActionProvider { } private _buildCtorActions(document: TextDocument, editor: TextEditor, actionTitle: string, command: string): Result { - return this._findCtorDefinitionAndProperties(document, editor) + return this._handleCtorDefinitionAndProperties(document, editor) .AndThenSync(classDefinition => { const parameter: ConstructorFromPropertiesArgument = { properties: classDefinition.properties, @@ -201,7 +201,7 @@ export default class CodeActionProvider implements VSCodeCodeActionProvider { }); } - private _findCtorDefinitionAndProperties(document: TextDocument, editor: TextEditor): Result { + private _handleCtorDefinitionAndProperties(document: TextDocument, editor: TextEditor): Result { const position = editor.selection.active; return this._findFileScopedNamespace(document) From 2ace63866f3179bbc4266f268a726e1999eee90b Mon Sep 17 00:00:00 2001 From: Sante Barbuto Date: Wed, 8 Nov 2023 23:37:07 +0100 Subject: [PATCH 2/7] chore: Refactored codeActionProvider --- src/codeActionProvider.ts | 70 +++++++++++++++++++++++++++------------ 1 file changed, 49 insertions(+), 21 deletions(-) diff --git a/src/codeActionProvider.ts b/src/codeActionProvider.ts index 1662fc0..cb0daf2 100644 --- a/src/codeActionProvider.ts +++ b/src/codeActionProvider.ts @@ -23,17 +23,25 @@ import { formatDocument } from './document/documentAction'; import { Logger } from './logging/log'; export default class CodeActionProvider implements VSCodeCodeActionProvider { - private _commandIds = { - ctorFromProperties: 'csharpextensions.ctorFromProperties', - bodyExpressionCtorFromProperties: 'csharpextensions.bodyExpressionCtorFromProperties', + private _actionsMapping: ActionMappingType = { + ctorFromProperties: { + command: 'csharpextensions.ctorFromProperties', + buildAction: this._buildCtorActions, + label: 'Initialize ctor from properties...', + }, + bodyExpressionCtorFromProperties: { + command: 'csharpextensions.bodyExpressionCtorFromProperties', + buildAction: this._buildCtorActions, + label: 'Initialize body expression ctor from properties...', + }, }; private static readonly ReadonlyRegex = new RegExp(/(public|private|protected)\s(\w+)\s(\w+)\s?{\s?(get;)\s?(private\s)?(set;)?\s?}/g); private static readonly ClassRegex = new RegExp(/(private|internal|public|protected)\s?(static)?\sclass\s(\w*)/g); constructor() { - commands.registerCommand(this._commandIds.ctorFromProperties, this.executeCtorFromProperties, this); - commands.registerCommand(this._commandIds.bodyExpressionCtorFromProperties, this.executeBodyExpressionCtorFromProperties, this); + commands.registerCommand(this._actionsMapping.ctorFromProperties.command, this.executeCtorFromProperties, this); + commands.registerCommand(this._actionsMapping.bodyExpressionCtorFromProperties.command, this.executeBodyExpressionCtorFromProperties, this); } public provideCodeActions(document: TextDocument, range: Range | Selection, context: CodeActionContext): CodeAction[] { @@ -51,14 +59,13 @@ export default class CodeActionProvider implements VSCodeCodeActionProvider { } const editor = resultEditor.value(); - const ctorActionResult = this._buildCtorActions(document, editor, 'Initialize ctor from properties...', this._commandIds.ctorFromProperties); - if (ctorActionResult.isOk()) { - codeActions.push(ctorActionResult.value()); - } - - const bodyExpressionCtorAction = this._buildCtorActions(document, editor, 'Initialize body expression ctor from properties...', this._commandIds.bodyExpressionCtorFromProperties); - if (bodyExpressionCtorAction.isOk()) { - codeActions.push(bodyExpressionCtorAction.value()); + for (const key in this._actionsMapping) { + const actionMappingKey = key as keyof ActionMappingType; + const { command, buildAction, label } = this._actionsMapping[actionMappingKey]; + const actionResult = buildAction({ document, editor, actionTitle: label, command }); + if (actionResult.isOk()) { + codeActions.push(actionResult.value()); + } } return codeActions; @@ -179,8 +186,10 @@ export default class CodeActionProvider implements VSCodeCodeActionProvider { } } - private _buildCtorActions(document: TextDocument, editor: TextEditor, actionTitle: string, command: string): Result { - return this._handleCtorDefinitionAndProperties(document, editor) + private _buildCtorActions(args: BuildActionArgument): Result { + const { document, editor, actionTitle, command } = args; + + return CodeActionProvider.handleCtorDefinitionAndProperties(document, editor) .AndThenSync(classDefinition => { const parameter: ConstructorFromPropertiesArgument = { properties: classDefinition.properties, @@ -201,11 +210,11 @@ export default class CodeActionProvider implements VSCodeCodeActionProvider { }); } - private _handleCtorDefinitionAndProperties(document: TextDocument, editor: TextEditor): Result { + private static handleCtorDefinitionAndProperties(document: TextDocument, editor: TextEditor): Result { const position = editor.selection.active; - return this._findFileScopedNamespace(document) - .AndThenSync((isFileScoped) => this._findClassFromLine(document, position.line) + return CodeActionProvider.findFileScopedNamespace(document) + .AndThenSync((isFileScoped) => CodeActionProvider.findClassFromLine(document, position.line) .AndThenSync((withinClass) => { const properties = new Array(); let lineNo = 0; @@ -215,7 +224,7 @@ export default class CodeActionProvider implements VSCodeCodeActionProvider { const match = Array.from(textLine.text.trim().matchAll(CodeActionProvider.ReadonlyRegex)); if (match.length > 0) { - const resultFoundClass = this._findClassFromLine(document, lineNo); + const resultFoundClass = CodeActionProvider.findClassFromLine(document, lineNo); if (resultFoundClass.isOk() && resultFoundClass.value().className === withinClass.className) { const prop: CSharpPropertyDefinition = { @@ -242,7 +251,7 @@ export default class CodeActionProvider implements VSCodeCodeActionProvider { })); } - private _findFileScopedNamespace(document: TextDocument): Result { + private static findFileScopedNamespace(document: TextDocument): Result { let lineNo = 0; let isFileScopedNamespace = false; while (lineNo < document.lineCount) { @@ -261,7 +270,7 @@ export default class CodeActionProvider implements VSCodeCodeActionProvider { return Result.error('NameSpaceNotFoundError', 'Class does not have a namespace'); } - private _findClassFromLine(document: TextDocument, lineNo: number): Result { + private static findClassFromLine(document: TextDocument, lineNo: number): Result { if (!lineNo) lineNo = document.lineCount - 1; if (lineNo >= document.lineCount) lineNo = document.lineCount - 1; @@ -293,3 +302,22 @@ interface ConstructorFromPropertiesArgument { properties: CSharpPropertyDefinition[], isFileScopedNamespace: boolean, } + +interface BuildActionArgument { + document: TextDocument; + editor: TextEditor; + actionTitle: string; + command: string; +} + +type BuildAction = (args: BuildActionArgument) => Result; +type MappingType = { + command: string; + buildAction: BuildAction; + label: string +}; + +type ActionMappingType = { + ctorFromProperties: MappingType; + bodyExpressionCtorFromProperties: MappingType; +}; From d961d0a645b242a4c32602d936046afdf2fb0776 Mon Sep 17 00:00:00 2001 From: bard83 Date: Sun, 23 Mar 2025 16:41:37 +0100 Subject: [PATCH 3/7] fix: Replace with in action provider class regex --- src/codeActionProvider.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/codeActionProvider.ts b/src/codeActionProvider.ts index cb0daf2..89a08bf 100644 --- a/src/codeActionProvider.ts +++ b/src/codeActionProvider.ts @@ -37,7 +37,7 @@ export default class CodeActionProvider implements VSCodeCodeActionProvider { }; private static readonly ReadonlyRegex = new RegExp(/(public|private|protected)\s(\w+)\s(\w+)\s?{\s?(get;)\s?(private\s)?(set;)?\s?}/g); - private static readonly ClassRegex = new RegExp(/(private|internal|public|protected)\s?(static)?\sclass\s(\w*)/g); + private static readonly ClassRegex = new RegExp(/(private|internal|public|protected)\s?(partial)?\sclass\s(\w*)/g); constructor() { commands.registerCommand(this._actionsMapping.ctorFromProperties.command, this.executeCtorFromProperties, this); From 25b9e6db5da7d361717397ae2281f00d2d7372be Mon Sep 17 00:00:00 2001 From: bard83 Date: Sun, 23 Mar 2025 17:16:18 +0100 Subject: [PATCH 4/7] feat: extend code actions to struct --- src/codeActionProvider.ts | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/codeActionProvider.ts b/src/codeActionProvider.ts index 89a08bf..02c8913 100644 --- a/src/codeActionProvider.ts +++ b/src/codeActionProvider.ts @@ -37,7 +37,7 @@ export default class CodeActionProvider implements VSCodeCodeActionProvider { }; private static readonly ReadonlyRegex = new RegExp(/(public|private|protected)\s(\w+)\s(\w+)\s?{\s?(get;)\s?(private\s)?(set;)?\s?}/g); - private static readonly ClassRegex = new RegExp(/(private|internal|public|protected)\s?(partial)?\sclass\s(\w*)/g); + private static readonly ClassStructRegex = new RegExp(/(private|internal|public|protected)\s?(partial)?\s?(record)?\s(class|struct)\s(\w*)/g); constructor() { commands.registerCommand(this._actionsMapping.ctorFromProperties.command, this.executeCtorFromProperties, this); @@ -214,8 +214,8 @@ export default class CodeActionProvider implements VSCodeCodeActionProvider { const position = editor.selection.active; return CodeActionProvider.findFileScopedNamespace(document) - .AndThenSync((isFileScoped) => CodeActionProvider.findClassFromLine(document, position.line) - .AndThenSync((withinClass) => { + .AndThenSync((isFileScoped) => CodeActionProvider.findClassOrStructFromLine(document, position.line) + .AndThenSync((withinClassOrStruct) => { const properties = new Array(); let lineNo = 0; @@ -224,12 +224,12 @@ export default class CodeActionProvider implements VSCodeCodeActionProvider { const match = Array.from(textLine.text.trim().matchAll(CodeActionProvider.ReadonlyRegex)); if (match.length > 0) { - const resultFoundClass = CodeActionProvider.findClassFromLine(document, lineNo); + const resultFoundClassOrStruct = CodeActionProvider.findClassOrStructFromLine(document, lineNo); - if (resultFoundClass.isOk() && resultFoundClass.value().className === withinClass.className) { + if (resultFoundClassOrStruct.isOk() && resultFoundClassOrStruct.value().className === withinClassOrStruct.className) { const prop: CSharpPropertyDefinition = { lineNumber: lineNo, - class: resultFoundClass.value(), + class: resultFoundClassOrStruct.value(), modifier: match[0][1], type: match[0][2], name: match[0][3], @@ -247,7 +247,7 @@ export default class CodeActionProvider implements VSCodeCodeActionProvider { return Result.error('NotFoundError', 'Properties not found'); } - return Result.ok({ properties, classDefinition: withinClass, isFileScoped }); + return Result.ok({ properties, classDefinition: withinClassOrStruct, isFileScoped }); })); } @@ -270,20 +270,20 @@ export default class CodeActionProvider implements VSCodeCodeActionProvider { return Result.error('NameSpaceNotFoundError', 'Class does not have a namespace'); } - private static findClassFromLine(document: TextDocument, lineNo: number): Result { + private static findClassOrStructFromLine(document: TextDocument, lineNo: number): Result { if (!lineNo) lineNo = document.lineCount - 1; if (lineNo >= document.lineCount) lineNo = document.lineCount - 1; while (lineNo >= 0) { const line = document.lineAt(lineNo); - const match = Array.from(line.text.trim().matchAll(CodeActionProvider.ClassRegex)); + const match = Array.from(line.text.trim().matchAll(CodeActionProvider.ClassStructRegex)); if (match.length > 0) { return Result.ok({ startLine: lineNo, endLine: -1, - className: match[0][3], + className: match[0][match[0].length - 1], modifier: match[0][1], statement: match[0][0] }); From 174de36d7e796e31e8f9fb412d9376170f25064a Mon Sep 17 00:00:00 2001 From: bard83 Date: Mon, 24 Mar 2025 10:35:12 +0100 Subject: [PATCH 5/7] chore: rename action provider formatDocument local function --- src/codeActionProvider.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/codeActionProvider.ts b/src/codeActionProvider.ts index 02c8913..70c7574 100644 --- a/src/codeActionProvider.ts +++ b/src/codeActionProvider.ts @@ -126,7 +126,7 @@ export default class CodeActionProvider implements VSCodeCodeActionProvider { const reFormatAfterChange = configuration.get('csharpextensions.reFormatAfterChange', true); if (reFormatAfterChange) { - await this.formatDocument(args.document.uri); + await this.performDocumentFormatting(args.document.uri); } } @@ -170,7 +170,7 @@ export default class CodeActionProvider implements VSCodeCodeActionProvider { const reFormatAfterChange = configuration.get('csharpextensions.reFormatAfterChange', true); if (reFormatAfterChange) { - await this.formatDocument(args.document.uri); + await this.performDocumentFormatting(args.document.uri); } } @@ -178,7 +178,7 @@ export default class CodeActionProvider implements VSCodeCodeActionProvider { return getIndentation(tabSize, indentation); } - private async formatDocument(documentUri: Uri) { + private async performDocumentFormatting(documentUri: Uri) { try { await formatDocument(documentUri); } catch (err) { From dbdc5e9a423b0249cb7a9e819cadd90b8eea3664 Mon Sep 17 00:00:00 2001 From: bard83 Date: Mon, 24 Mar 2025 10:36:42 +0100 Subject: [PATCH 6/7] chore: rename ReadonlyRegex into PropertyRegex --- src/codeActionProvider.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/codeActionProvider.ts b/src/codeActionProvider.ts index 70c7574..7fe7997 100644 --- a/src/codeActionProvider.ts +++ b/src/codeActionProvider.ts @@ -36,7 +36,7 @@ export default class CodeActionProvider implements VSCodeCodeActionProvider { }, }; - private static readonly ReadonlyRegex = new RegExp(/(public|private|protected)\s(\w+)\s(\w+)\s?{\s?(get;)\s?(private\s)?(set;)?\s?}/g); + private static readonly PropertyRegex = new RegExp(/(public|private|protected)\s(\w+)\s(\w+)\s?{\s?(get;)\s?(private\s)?(set;)?\s?}/g); private static readonly ClassStructRegex = new RegExp(/(private|internal|public|protected)\s?(partial)?\s?(record)?\s(class|struct)\s(\w*)/g); constructor() { @@ -222,7 +222,7 @@ export default class CodeActionProvider implements VSCodeCodeActionProvider { while (lineNo < document.lineCount) { const textLine = document.lineAt(lineNo); - const match = Array.from(textLine.text.trim().matchAll(CodeActionProvider.ReadonlyRegex)); + const match = Array.from(textLine.text.trim().matchAll(CodeActionProvider.PropertyRegex)); if (match.length > 0) { const resultFoundClassOrStruct = CodeActionProvider.findClassOrStructFromLine(document, lineNo); From 4461fada5f16c8c7b42823f383625c27c03e545d Mon Sep 17 00:00:00 2001 From: bard83 Date: Mon, 24 Mar 2025 10:46:47 +0100 Subject: [PATCH 7/7] feat: wip --- src/codeActionProvider.ts | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/codeActionProvider.ts b/src/codeActionProvider.ts index 7fe7997..223e107 100644 --- a/src/codeActionProvider.ts +++ b/src/codeActionProvider.ts @@ -34,10 +34,21 @@ export default class CodeActionProvider implements VSCodeCodeActionProvider { buildAction: this._buildCtorActions, label: 'Initialize body expression ctor from properties...', }, + recordStruct: { + command: 'csharpextensions.recordStruct', + buildAction: this._buildStructActions, + label: 'Convert to record struct...', + }, + readonlyStruct: { + command: 'csharpextensions.readonlyStruct', + buildAction: this._buildStructActions, + label: 'Convert to readonly struct...', + }, }; private static readonly PropertyRegex = new RegExp(/(public|private|protected)\s(\w+)\s(\w+)\s?{\s?(get;)\s?(private\s)?(set;)?\s?}/g); private static readonly ClassStructRegex = new RegExp(/(private|internal|public|protected)\s?(partial)?\s?(record)?\s(class|struct)\s(\w*)/g); + private static readonly StructRegex = new RegExp(/(private|internal|public|protected)\s?(readonly)?\s?(partial)?\s?(record)?\sstruct\s(\w*)/g); constructor() { commands.registerCommand(this._actionsMapping.ctorFromProperties.command, this.executeCtorFromProperties, this); @@ -210,6 +221,12 @@ export default class CodeActionProvider implements VSCodeCodeActionProvider { }); } + private _buildStructActions(args: BuildActionArgument): Result { + console.log(args); + + return Result.error('NotImplemented', 'method not implemented'); + } + private static handleCtorDefinitionAndProperties(document: TextDocument, editor: TextEditor): Result { const position = editor.selection.active; @@ -320,4 +337,6 @@ type MappingType = { type ActionMappingType = { ctorFromProperties: MappingType; bodyExpressionCtorFromProperties: MappingType; + recordStruct: MappingType; + readonlyStruct: MappingType; };