diff --git a/src/PluginInterface.ts b/src/PluginInterface.ts index 2499736dd..05f1dba26 100644 --- a/src/PluginInterface.ts +++ b/src/PluginInterface.ts @@ -165,7 +165,8 @@ export default class PluginInterface { beforeFileValidate: 'beforeValidateFile', onFileValidate: 'validateFile', afterFileValidate: 'afterValidateFile', - onSerializeProgram: 'serializeProgram' + onSerializeProgram: 'serializeProgram', + onGetSourceFixAllCodeActions: 'provideSourceFixAllCodeActions' }; for (const [oldEvent, newEvent] of Object.entries(upgradeWithWarn)) { diff --git a/src/Program.ts b/src/Program.ts index 362d612c4..5d9d75ec0 100644 --- a/src/Program.ts +++ b/src/Program.ts @@ -8,7 +8,7 @@ import { Scope } from './Scope'; import type { NamespaceContainer, NamespaceFileContribution } from './Scope'; import { SymbolTable } from './SymbolTable'; import { DiagnosticMessages } from './DiagnosticMessages'; -import type { FileObj, SemanticToken, FileLink, ProvideHoverEvent, ProvideCompletionsEvent, Hover, ProvideDefinitionEvent, ProvideReferencesEvent, ProvideDocumentSymbolsEvent, ProvideWorkspaceSymbolsEvent, BeforeAddFileEvent, BeforeRemoveFileEvent, PrepareFileEvent, PrepareProgramEvent, ProvideFileEvent, SerializedFile, TranspileObj, SerializeFileEvent, ScopeValidationOptions, ExtraSymbolData, ProvideSelectionRangesEvent, OnGetSourceFixAllCodeActionsEvent } from './interfaces'; +import type { FileObj, SemanticToken, FileLink, ProvideHoverEvent, ProvideCompletionsEvent, Hover, ProvideDefinitionEvent, ProvideReferencesEvent, ProvideDocumentSymbolsEvent, ProvideWorkspaceSymbolsEvent, BeforeAddFileEvent, BeforeRemoveFileEvent, PrepareFileEvent, PrepareProgramEvent, ProvideFileEvent, SerializedFile, TranspileObj, SerializeFileEvent, ScopeValidationOptions, ExtraSymbolData, ProvideSelectionRangesEvent, ProvideSourceFixAllCodeActionsEvent } from './interfaces'; import type { SourceFixAllCodeAction } from './CodeActionUtil'; import { codeActionUtil } from './CodeActionUtil'; import { standardizePath as s, util } from './util'; @@ -767,6 +767,8 @@ export class Program { this.files[file.srcPath.toLowerCase()] = file; this.destMap.set(file.destPath.toLowerCase(), file); + this.plugins.emit('addFile', fileAddEvent); + this.plugins.emit('afterAddFile', fileAddEvent); return file; @@ -1036,6 +1038,7 @@ export class Program { const event: BeforeRemoveFileEvent = { file: file, program: this }; this.plugins.emit('beforeRemoveFile', event); + this.plugins.emit('removeFile', event); //if there is a scope named the same as this file's path, remove it (i.e. xml scopes) let scope = this.scopes[file.destPath]; @@ -1906,8 +1909,9 @@ export class Program { /** * Compute "source fix all" code actions for the given file. - * Fires the `onGetSourceFixAllCodeActions` plugin event with all diagnostics for the file (no range filter), - * then converts each contributed SourceFixAllCodeAction into an LSP CodeAction. + * Fires the `provideSourceFixAllCodeActions` plugin event (along with its before/after variants) + * with all diagnostics for the file (no range filter), then converts each contributed + * SourceFixAllCodeAction into an LSP CodeAction. */ public getSourceFixAllCodeActions(srcPath: string): CodeAction[] { const actions: SourceFixAllCodeAction[] = []; @@ -1918,13 +1922,16 @@ export class Program { .getDiagnostics() .filter(x => x.location?.uri === fileUri); const scopes = this.getScopesForFile(file); - this.plugins.emit('onGetSourceFixAllCodeActions', { + const event: ProvideSourceFixAllCodeActionsEvent = { program: this, file: file, diagnostics: diagnostics, scopes: scopes, actions: actions - } as OnGetSourceFixAllCodeActionsEvent); + }; + this.plugins.emit('beforeProvideSourceFixAllCodeActions', event); + this.plugins.emit('provideSourceFixAllCodeActions', event); + this.plugins.emit('afterProvideSourceFixAllCodeActions', event); } return actions.map(action => codeActionUtil.createCodeAction({ ...action, @@ -2195,6 +2202,9 @@ export class Program { files: files, outDir: outDir }); + + await this.plugins.emitAsync('writeProgram', programEvent); + //empty the out directory await fsExtra.emptyDir(outDir); @@ -2238,6 +2248,8 @@ export class Program { files: options?.files ?? Object.values(this.files) }); + await this.plugins.emitAsync('buildProgram', event); + //prepare the program (and files) for building event.files = await this.prepare(event.files); diff --git a/src/bscPlugin/BscPlugin.ts b/src/bscPlugin/BscPlugin.ts index 299a6b7e3..edd2d21c8 100644 --- a/src/bscPlugin/BscPlugin.ts +++ b/src/bscPlugin/BscPlugin.ts @@ -1,5 +1,5 @@ import { isBrsFile, isXmlFile } from '../astUtils/reflection'; -import type { Plugin, ValidateFileEvent, ProvideCodeActionsEvent, ProvideHoverEvent, ProvideSemanticTokensEvent, ValidateScopeEvent, ProvideCompletionsEvent, ProvideDefinitionEvent, ProvideReferencesEvent, ProvideDocumentSymbolsEvent, ProvideWorkspaceSymbolsEvent, AfterProvideFileEvent, AfterValidateFileEvent, AfterValidateProgramEvent, AfterSerializeFileEvent, BeforeBuildProgramEvent, OnPrepareFileEvent, WriteFileEvent, OnGetSourceFixAllCodeActionsEvent, ProvideSelectionRangesEvent } from '../interfaces'; +import type { Plugin, ValidateFileEvent, ProvideCodeActionsEvent, ProvideHoverEvent, ProvideSemanticTokensEvent, ValidateScopeEvent, ProvideCompletionsEvent, ProvideDefinitionEvent, ProvideReferencesEvent, ProvideDocumentSymbolsEvent, ProvideWorkspaceSymbolsEvent, AfterProvideFileEvent, AfterValidateFileEvent, AfterValidateProgramEvent, AfterSerializeFileEvent, BeforeBuildProgramEvent, OnPrepareFileEvent, WriteFileEvent, ProvideSourceFixAllCodeActionsEvent, ProvideSelectionRangesEvent } from '../interfaces'; import { CodeActionsProcessor } from './codeActions/CodeActionsProcessor'; import { FixAllCodeActionsProcessor } from './codeActions/FixAllCodeActionsProcessor'; import { CompletionsProcessor } from './completions/CompletionsProcessor'; @@ -35,7 +35,7 @@ export class BscPlugin implements Plugin { new CodeActionsProcessor(event).process(); } - public onGetSourceFixAllCodeActions(event: OnGetSourceFixAllCodeActionsEvent) { + public provideSourceFixAllCodeActions(event: ProvideSourceFixAllCodeActionsEvent) { new FixAllCodeActionsProcessor(event).process(); } diff --git a/src/bscPlugin/codeActions/FixAllCodeActionsProcessor.ts b/src/bscPlugin/codeActions/FixAllCodeActionsProcessor.ts index 201e6e716..e1721d531 100644 --- a/src/bscPlugin/codeActions/FixAllCodeActionsProcessor.ts +++ b/src/bscPlugin/codeActions/FixAllCodeActionsProcessor.ts @@ -2,13 +2,13 @@ import type { BsDiagnostic } from '../../interfaces'; import { DiagnosticCodeMap } from '../../DiagnosticMessages'; import type { DiagnosticMessageType } from '../../DiagnosticMessages'; import type { XmlFile } from '../../files/XmlFile'; -import type { OnGetSourceFixAllCodeActionsEvent } from '../../interfaces'; +import type { ProvideSourceFixAllCodeActionsEvent } from '../../interfaces'; import { isXmlFile } from '../../astUtils/reflection'; import { getMissingExtendsInsertPosition, getRemoveReturnValueChange } from './codeActionHelpers'; export class FixAllCodeActionsProcessor { public constructor( - public event: OnGetSourceFixAllCodeActionsEvent + public event: ProvideSourceFixAllCodeActionsEvent ) { } public process() { diff --git a/src/interfaces.ts b/src/interfaces.ts index be32573f9..8cccdc6d0 100644 --- a/src/interfaces.ts +++ b/src/interfaces.ts @@ -281,13 +281,21 @@ export interface Plugin { removeProgram?(event: RemoveProgramEvent): any; afterRemoveProgram?(event: AfterRemoveProgramEvent): any; + /** + * Called before the `provideSourceFixAllCodeActions` hook. + */ + beforeProvideSourceFixAllCodeActions?(event: BeforeProvideSourceFixAllCodeActionsEvent): any; /** * Emitted when VS Code requests "source fix all" source actions for a file. * Plugins push one or more `SourceFixAllCodeAction` objects onto `event.actions`, * each representing a distinct named group that will appear in the Source Actions menu. * Plugins are responsible for assembling and merging all changes within each action. */ - onGetSourceFixAllCodeActions?(event: OnGetSourceFixAllCodeActionsEvent): any; + provideSourceFixAllCodeActions?(event: ProvideSourceFixAllCodeActionsEvent): any; + /** + * Called after `provideSourceFixAllCodeActions`. Use this to intercept or sanitize the actions before they are converted to LSP CodeActions. + */ + afterProvideSourceFixAllCodeActions?(event: AfterProvideSourceFixAllCodeActionsEvent): any; /** * Emitted before the program starts collecting completions @@ -437,6 +445,11 @@ export interface Plugin { * Includes physical files as well as any virtual files produced by `provideFile` events */ beforeAddFile?(event: BeforeAddFileEvent): any; + /** + * Called while a file is being added to the program. This is the central event fired between `beforeAddFile` and `afterAddFile`. + * Includes physical files as well as any virtual files produced by `provideFile` events + */ + addFile?(event: AddFileEvent): any; /** * Called after a file has been added to the program. * Includes physical files as well as any virtual files produced by `provideFile` events @@ -447,6 +460,11 @@ export interface Plugin { * Called before a file is removed from the program. This includes physical and virtual files */ beforeRemoveFile?(event: BeforeRemoveFileEvent): any; + /** + * Called while a file is being removed from the program. This is the central event fired between `beforeRemoveFile` and `afterRemoveFile`. + * This includes physical and virtual files + */ + removeFile?(event: RemoveFileEvent): any; /** * Called after a file has been removed from the program. This includes physical and virtual files */ @@ -471,6 +489,10 @@ export interface Plugin { * Called right before the program builds (i.e. generates the code and puts it in the outDir */ beforeBuildProgram?(event: BeforeBuildProgramEvent): any; + /** + * Called while the program builds. This is the central event fired between `beforeBuildProgram` and `afterBuildProgram`. + */ + buildProgram?(event: BuildProgramEvent): any; /** * Called right after the program builds (i.e. generates the code and puts it in the outDir */ @@ -523,6 +545,10 @@ export interface Plugin { * Called before any files are written */ beforeWriteProgram?(event: BeforeWriteProgramEvent): any; + /** + * Called while files are being written. This is the central event fired between `beforeWriteProgram` and `afterWriteProgram`. + */ + writeProgram?(event: WriteProgramEvent): any; /** * Called after all files are written */ @@ -592,7 +618,7 @@ export interface AfterValidateProgramEvent extends BeforeValidateProgramEvent { wasCancelled: boolean; } -export interface OnGetSourceFixAllCodeActionsEvent { +export interface ProvideSourceFixAllCodeActionsEvent { program: Program; file: BscFile; /** All diagnostics for this file (not range-filtered) */ @@ -604,6 +630,12 @@ export interface OnGetSourceFixAllCodeActionsEvent { */ actions: SourceFixAllCodeAction[]; } +export type BeforeProvideSourceFixAllCodeActionsEvent = ProvideSourceFixAllCodeActionsEvent; +export type AfterProvideSourceFixAllCodeActionsEvent = ProvideSourceFixAllCodeActionsEvent; +/** + * @deprecated use `ProvideSourceFixAllCodeActionsEvent` instead + */ +export type OnGetSourceFixAllCodeActionsEvent = ProvideSourceFixAllCodeActionsEvent; export interface ProvideCompletionsEvent { @@ -625,6 +657,7 @@ export interface BeforeBuildProgramEvent { files: BscFile[]; editor: Editor; } +export type BuildProgramEvent = BeforeBuildProgramEvent; export type AfterBuildProgramEvent = BeforeBuildProgramEvent; export interface ProvideHoverEvent { @@ -926,12 +959,14 @@ export interface BeforeAddFileEvent { file: TFile; program: Program; } +export type AddFileEvent = BeforeAddFileEvent; export type AfterAddFileEvent = BeforeAddFileEvent; export interface BeforeRemoveFileEvent { file: TFile; program: Program; } +export type RemoveFileEvent = BeforeRemoveFileEvent; export type AfterRemoveFileEvent = BeforeRemoveFileEvent; export type BeforePrepareProgramEvent = PrepareProgramEvent; @@ -1020,6 +1055,7 @@ export interface BeforeWriteProgramEvent { outDir: string; files: Map; } +export type WriteProgramEvent = BeforeWriteProgramEvent; export type AfterWriteProgramEvent = BeforeWriteProgramEvent;