diff --git a/src/commands/project.ts b/src/commands/project.ts index 8da78de2..ae13ae1b 100644 --- a/src/commands/project.ts +++ b/src/commands/project.ts @@ -140,8 +140,9 @@ export async function createProject(node: NodeBase | undefined, api?: AtelierAPI // Technically a project is a "document", so tell the server that we created it try { - await new StudioActions().fireProjectUserAction(api, name, OtherStudioAction.CreatedNewDocument); - await new StudioActions().fireProjectUserAction(api, name, OtherStudioAction.FirstTimeDocumentSave); + const studioActions = new StudioActions(); + await studioActions.fireProjectUserAction(api, name, OtherStudioAction.CreatedNewDocument); + await studioActions.fireProjectUserAction(api, name, OtherStudioAction.FirstTimeDocumentSave); } catch (error) { let message = `Source control actions failed for project '${name}'.`; if (error && error.errorText && error.errorText !== "") { @@ -149,7 +150,7 @@ export async function createProject(node: NodeBase | undefined, api?: AtelierAPI outputChannel.show(true); message += " Check 'ObjectScript' output channel for details."; } - return vscode.window.showErrorMessage(message, "Dismiss"); + vscode.window.showErrorMessage(message, "Dismiss"); } // Refresh the explorer @@ -204,7 +205,7 @@ export async function deleteProject(node: ProjectNode | undefined): Promise outputChannel.show(true); message += " Check 'ObjectScript' output channel for details."; } - return vscode.window.showErrorMessage(message, "Dismiss"); + vscode.window.showErrorMessage(message, "Dismiss"); } // Refresh the explorer @@ -736,17 +737,9 @@ export async function modifyProject( } // Technically a project is a "document", so tell the server that we're opening it - try { - await new StudioActions().fireProjectUserAction(api, project, OtherStudioAction.OpenedDocument); - } catch (error) { - let message = `'OpenedDocument' source control action failed for project '${project}'.`; - if (error && error.errorText && error.errorText !== "") { - outputChannel.appendLine("\n" + error.errorText); - outputChannel.show(true); - message += " Check 'ObjectScript' output channel for details."; - } - return vscode.window.showErrorMessage(message, "Dismiss"); - } + await new StudioActions() + .fireProjectUserAction(api, project, OtherStudioAction.OpenedDocument) + .catch(/* Swallow error because showing it is more disruptive than using a potentially outdated project definition */); let items: ProjectItem[] = await api .actionQuery("SELECT Name, Type FROM %Studio.Project_ProjectItemsList(?,?) WHERE Type != 'GBL'", [project, "1"]) diff --git a/src/commands/unitTest.ts b/src/commands/unitTest.ts index ea5f2d45..0d129351 100644 --- a/src/commands/unitTest.ts +++ b/src/commands/unitTest.ts @@ -5,6 +5,7 @@ import { getFileText, methodOffsetToLine, outputChannel, stripClassMemberNameQuo import { fileSpecFromURI } from "../utils/FileProviderUtil"; import { AtelierAPI } from "../api"; import { DocumentContentProvider } from "../providers/DocumentContentProvider"; +import { StudioActions, OtherStudioAction } from "./studio"; enum TestStatus { Failed = 0, @@ -259,7 +260,7 @@ function replaceRootTestItems(testController: vscode.TestController): void { } /** Create a `Promise` that resolves to a query result containing an array of children for `item`. */ -function childrenForServerSideFolderItem( +async function childrenForServerSideFolderItem( item: vscode.TestItem ): Promise>> { let query: string; @@ -275,6 +276,10 @@ function childrenForServerSideFolderItem( const params = new URLSearchParams(item.uri.query); const api = new AtelierAPI(item.uri); if (params.has("project")) { + // Technically a project is a "document", so tell the server that we're opening it + await new StudioActions() + .fireProjectUserAction(api, params.get("project"), OtherStudioAction.OpenedDocument) + .catch(/* Swallow error because showing it is more disruptive than using a potentially outdated project definition */); query = "SELECT DISTINCT CASE " + "WHEN $LENGTH(SUBSTR(Name,?),'.') > 1 THEN $PIECE(SUBSTR(Name,?),'.') " + diff --git a/src/explorer/explorer.ts b/src/explorer/explorer.ts index 76684c25..cad90a62 100644 --- a/src/explorer/explorer.ts +++ b/src/explorer/explorer.ts @@ -6,6 +6,7 @@ import { config, OBJECTSCRIPT_FILE_SCHEMA, projectsExplorerProvider } from "../e import { WorkspaceNode } from "./models/workspaceNode"; import { outputChannel } from "../utils"; import { DocumentContentProvider } from "../providers/DocumentContentProvider"; +import { StudioActions, OtherStudioAction } from "../commands/studio"; /** Get the URI for this leaf node */ export function getLeafNodeUri(node: NodeBase, forceServerCopy = false): vscode.Uri { @@ -74,6 +75,20 @@ export function registerExplorerOpen(): vscode.Disposable { if (remove == "Yes") { const api = new AtelierAPI(uri); try { + // Technically a project is a "document", so tell the server that we're editing it + const studioActions = new StudioActions(); + await studioActions.fireProjectUserAction(api, project, OtherStudioAction.AttemptedEdit); + if (studioActions.projectEditAnswer != "1") { + // Don't perform the edit + if (studioActions.projectEditAnswer == "-1") { + // Source control action failed + vscode.window.showErrorMessage( + `'AttemptedEdit' source control action failed for project '${project}'. Check the 'ObjectScript' Output channel for details.`, + "Dismiss" + ); + } + return; + } // Remove the item from the project let prjFileName = fullName.startsWith("/") ? fullName.slice(1) : fullName; const ext = prjFileName.split(".").pop().toLowerCase(); diff --git a/src/explorer/models/projectNode.ts b/src/explorer/models/projectNode.ts index ef365578..5ab0b8f5 100644 --- a/src/explorer/models/projectNode.ts +++ b/src/explorer/models/projectNode.ts @@ -18,7 +18,9 @@ export class ProjectNode extends NodeBase { // Technically a project is a "document", so tell the server that we're opening it const api = new AtelierAPI(this.workspaceFolderUri); api.setNamespace(this.namespace); - await new StudioActions().fireProjectUserAction(api, this.label, OtherStudioAction.OpenedDocument); + await new StudioActions() + .fireProjectUserAction(api, this.label, OtherStudioAction.OpenedDocument) + .catch(/* Swallow error because showing it is more disruptive than using a potentially outdated project definition */); node = new ProjectRootNode( "Classes", diff --git a/src/providers/FileSystemProvider/FileSearchProvider.ts b/src/providers/FileSystemProvider/FileSearchProvider.ts index efa279f7..087b16e0 100644 --- a/src/providers/FileSystemProvider/FileSearchProvider.ts +++ b/src/providers/FileSystemProvider/FileSearchProvider.ts @@ -3,6 +3,8 @@ import { projectContentsFromUri, studioOpenDialogFromURI } from "../../utils/Fil import { notNull } from "../../utils"; import { DocumentContentProvider } from "../DocumentContentProvider"; import { ProjectItem } from "../../commands/project"; +import { StudioActions, OtherStudioAction } from "../../commands/studio"; +import { AtelierAPI } from "../../api"; export class FileSearchProvider implements vscode.FileSearchProvider { /** @@ -11,20 +13,25 @@ export class FileSearchProvider implements vscode.FileSearchProvider { * @param options A set of options to consider while searching files. * @param token A cancellation token. */ - public provideFileSearchResults( + public async provideFileSearchResults( query: vscode.FileSearchQuery, options: vscode.FileSearchOptions, token: vscode.CancellationToken - ): vscode.ProviderResult { + ): Promise { let counter = 0; let pattern = query.pattern.charAt(0) == "/" ? query.pattern.slice(1) : query.pattern; const params = new URLSearchParams(options.folder.query); const csp = params.has("csp") && ["", "1"].includes(params.get("csp")); if (params.has("project") && params.get("project").length) { - const patternRegex = new RegExp(`.*${pattern}.*`.replace(/\.|\//g, "[./]"), "i"); + // Technically a project is a "document", so tell the server that we're opening it + await new StudioActions() + .fireProjectUserAction(new AtelierAPI(options.folder), params.get("project"), OtherStudioAction.OpenedDocument) + .catch(/* Swallow error because showing it is more disruptive than using a potentially outdated project definition */); if (token.isCancellationRequested) { return; } + + const patternRegex = new RegExp(`.*${pattern}.*`.replace(/\.|\//g, "[./]"), "i"); return projectContentsFromUri(options.folder, true).then((docs) => docs .map((doc: ProjectItem) => { diff --git a/src/providers/FileSystemProvider/FileSystemProvider.ts b/src/providers/FileSystemProvider/FileSystemProvider.ts index ad78f3cc..26da3b6c 100644 --- a/src/providers/FileSystemProvider/FileSystemProvider.ts +++ b/src/providers/FileSystemProvider/FileSystemProvider.ts @@ -204,13 +204,9 @@ export class FileSystemProvider implements vscode.FileSystemProvider { if (params.has("project") && params.get("project").length) { if (["", "/"].includes(uri.path)) { // Technically a project is a "document", so tell the server that we're opening it - try { - await new StudioActions().fireProjectUserAction(api, params.get("project"), OtherStudioAction.OpenedDocument); - } catch { - throw vscode.FileSystemError.Unavailable( - `'OpenedDocument' source control action failed for '${params.get("project")}.PRJ'` - ); - } + await new StudioActions() + .fireProjectUserAction(api, params.get("project"), OtherStudioAction.OpenedDocument) + .catch(/* Swallow error because showing it is more disruptive than using a potentially outdated project definition */); } // Get all items in the project diff --git a/src/providers/FileSystemProvider/TextSearchProvider.ts b/src/providers/FileSystemProvider/TextSearchProvider.ts index 98979157..83853ba0 100644 --- a/src/providers/FileSystemProvider/TextSearchProvider.ts +++ b/src/providers/FileSystemProvider/TextSearchProvider.ts @@ -6,6 +6,7 @@ import { DocumentContentProvider } from "../DocumentContentProvider"; import { notNull, outputChannel, throttleRequests } from "../../utils"; import { config } from "../../extension"; import { fileSpecFromURI } from "../../utils/FileProviderUtil"; +import { OtherStudioAction, StudioActions } from "../../commands/studio"; /** * Convert an `attrline` in a description to a line number in document `content`. @@ -395,6 +396,16 @@ export class TextSearchProvider implements vscode.TextSearchProvider { // Needed because the server matches the full line against the regex and ignores the case parameter when in regex mode const pattern = query.isRegExp ? `${!query.isCaseSensitive ? "(?i)" : ""}.*${query.pattern}.*` : query.pattern; + if (params.has("project") && params.get("project").length) { + // Technically a project is a "document", so tell the server that we're opening it + await new StudioActions() + .fireProjectUserAction(api, params.get("project"), OtherStudioAction.OpenedDocument) + .catch(/* Swallow error because showing it is more disruptive than using a potentially outdated project definition */); + } + if (token.isCancellationRequested) { + return; + } + if (api.config.apiVersion >= 6) { // Build the request object const project = params.has("project") && params.get("project").length ? params.get("project") : undefined;