diff --git a/package.json b/package.json index 6c58d5e4..ba5d3d05 100644 --- a/package.json +++ b/package.json @@ -1310,7 +1310,14 @@ "objectscript.serverSourceControl.disableOtherActionTriggers": { "description": "Prevent server-side source control 'other action' triggers from firing.", "type": "boolean", - "scope": "resource" + "scope": "resource", + "default": false + }, + "objectscript.serverSourceControl.respectEditableStatus": { + "markdownDescription": "Set `isfs` document readonly if GetStatus method of server-side source control class returns Editable = 0.", + "type": "boolean", + "scope": "resource", + "default": false }, "objectscript.export": { "type": "object", @@ -1688,7 +1695,8 @@ }, "stopOnEntry": { "type": "boolean", - "description": "Automatically stop target after attach. If not specified, target does not stop." + "description": "Automatically stop target after attach. If not specified, target does not stop.", + "default": false } } } diff --git a/src/providers/FileSystemProvider/File.ts b/src/providers/FileSystemProvider/File.ts index 801c02da..fd4776c5 100644 --- a/src/providers/FileSystemProvider/File.ts +++ b/src/providers/FileSystemProvider/File.ts @@ -5,6 +5,7 @@ export class File implements vscode.FileStat { public ctime: number; public mtime: number; public size: number; + public permissions?: vscode.FilePermission; public fileName: string; public name: string; public data?: Uint8Array; diff --git a/src/providers/FileSystemProvider/FileSystemProvider.ts b/src/providers/FileSystemProvider/FileSystemProvider.ts index 37454a2b..a9a8ed55 100644 --- a/src/providers/FileSystemProvider/FileSystemProvider.ts +++ b/src/providers/FileSystemProvider/FileSystemProvider.ts @@ -13,7 +13,14 @@ import { redirectDotvscodeRoot, workspaceFolderOfUri, } from "../../utils/index"; -import { config, FILESYSTEM_SCHEMA, intLangId, macLangId, workspaceState } from "../../extension"; +import { + config, + FILESYSTEM_READONLY_SCHEMA, + FILESYSTEM_SCHEMA, + intLangId, + macLangId, + workspaceState, +} from "../../extension"; import { addIsfsFileToProject, modifyProject } from "../../commands/project"; import { DocumentContentProvider } from "../DocumentContentProvider"; import { Document, UserAction } from "../../api/atelier"; @@ -184,13 +191,55 @@ export class FileSystemProvider implements vscode.FileSystemProvider { this._fireSoon({ type: vscode.FileChangeType.Changed, uri }); } - public stat(uri: vscode.Uri): Promise { + public async stat(uri: vscode.Uri): Promise { + let entryPromise: Promise; + let result: Entry; const redirectedUri = redirectDotvscodeRoot(uri); if (redirectedUri.path !== uri.path) { // When redirecting the /.vscode subtree we must fill in as-yet-unvisited folders to fix https://github.com/intersystems-community/vscode-objectscript/issues/1143 - return this._lookup(redirectedUri, true); + entryPromise = this._lookup(redirectedUri, true); + } else { + entryPromise = this._lookup(uri); + } + + // If this is our readonly variant there's no point checking server-side whether the file sould be marked readonly + if (uri.scheme === FILESYSTEM_READONLY_SCHEMA) { + return entryPromise; + } + + if (entryPromise instanceof File) { + // previously resolved as a file + result = entryPromise; + } else if (entryPromise instanceof Promise && uri.path.split("/").pop()?.split(".").length > 1) { + // apparently a file, so resolve ahead of adding permissions + result = await entryPromise; + } else { + // otherwise return the promise + return entryPromise; + } + + // + if (result instanceof File) { + const api = new AtelierAPI(uri); + const serverName = isCSPFile(uri) ? uri.path : uri.path.slice(1).replace(/\//g, "."); + if (serverName.slice(-4).toLowerCase() == ".cls") { + if (await isClassDeployed(serverName, api)) { + result.permissions |= vscode.FilePermission.Readonly; + return result; + } + } + + // Does server-side source control report it as editable? + if (vscode.workspace.getConfiguration("objectscript.serverSourceControl", uri)?.get("respectEditableStatus")) { + const query = "select * from %Atelier_v1_Utils.Extension_GetStatus(?)"; + const statusObj = await api.actionQuery(query, [serverName]); + const docStatus = statusObj.result?.content?.pop(); + if (docStatus) { + result.permissions = docStatus.editable ? undefined : result.permissions | vscode.FilePermission.Readonly; + } + } } - return this._lookup(uri); + return result; } public async readDirectory(uri: vscode.Uri): Promise<[string, vscode.FileType][]> {