Skip to content

Check if /_vscode web app exists before redirecting .vscode files #1602

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
93 changes: 58 additions & 35 deletions src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -446,21 +446,6 @@ export async function checkConnection(
serverVersion: info.result.content.version,
healthshare: hasHS ? "yes" : "no",
});

// Update CSP web app cache if required
const key = `${api.serverId}:${api.config.ns}`.toLowerCase();
if (!cspApps.has(key)) {
cspApps.set(key, await api.getCSPApps().then((data) => data.result.content || []));
}
if (!otherDocExts.has(key)) {
otherDocExts.set(
key,
await api
.actionQuery("SELECT Extention FROM %Library.RoutineMgr_DocumentTypes()", [])
.then((data) => data.result?.content?.map((e) => e.Extention) ?? [])
.catch(() => [])
);
}
if (!api.externalServer) {
await setConnectionState(configName, true);
}
Expand Down Expand Up @@ -756,6 +741,44 @@ function setExplorerContextKeys(): void {
);
}

/** Cache the lists of web apps and abstract document types for all server-namespaces in `wsFolders` */
async function updateWebAndAbstractDocsCaches(wsFolders: readonly vscode.WorkspaceFolder[]): Promise<any> {
if (!wsFolders?.length) return;
const keys: Set<string> = new Set();
const connections: { key: string; api: AtelierAPI }[] = [];
// Filter out any duplicate connections
for (const wsFolder of wsFolders) {
const api = new AtelierAPI(wsFolder.uri);
if (!api.active) continue;
const key = `${api.serverId}:${api.config.ns}`.toLowerCase();
if (keys.has(key)) continue;
keys.add(key);
connections.push({ key, api });
}
return Promise.allSettled(
connections.map(async (connection) => {
if (!cspApps.has(connection.key)) {
cspApps.set(
connection.key,
await connection.api
.getCSPApps()
.then((data) => data.result.content ?? [])
.catch(() => [])
);
}
if (!otherDocExts.has(connection.key)) {
otherDocExts.set(
connection.key,
await connection.api
.actionQuery("SELECT Extention FROM %Library.RoutineMgr_DocumentTypes()", [])
.then((data) => data.result?.content?.map((e) => e.Extention) ?? [])
.catch(() => [])
);
}
})
);
}

/** The URIs of all classes that have been opened. Used when `objectscript.openClassContracted` is true */
let openedClasses: string[];

Expand Down Expand Up @@ -847,9 +870,9 @@ export async function activate(context: vscode.ExtensionContext): Promise<any> {
continue;
}
}
await Promise.allSettled(
vscode.workspace.workspaceFolders?.map((wsFolder) => addWsServerRootFolderData(wsFolder.uri)) || []
);

await updateWebAndAbstractDocsCaches(vscode.workspace.workspaceFolders);
await addWsServerRootFolderData(vscode.workspace.workspaceFolders);

xmlContentProvider = new XmlContentProvider();

Expand Down Expand Up @@ -1373,22 +1396,6 @@ export async function activate(context: vscode.ExtensionContext): Promise<any> {
},
supportsMultipleEditorsPerDocument: false,
}),
vscode.workspace.onDidChangeWorkspaceFolders(async ({ added }) => {
// Make sure we have a resolved connection spec for the targets of all added folders
const toCheck = new Map<string, vscode.Uri>();
added.map((workspaceFolder) => {
const uri = workspaceFolder.uri;
const { configName } = connectionTarget(uri);
toCheck.set(configName, uri);
});
for await (const oneToCheck of toCheck) {
const configName = oneToCheck[0];
const uri = oneToCheck[1];
const serverName = notIsfs(uri) ? config("conn", configName).server : configName;
await resolveConnectionSpec(serverName);
}
await Promise.allSettled(added.map((wsFolder) => addWsServerRootFolderData(wsFolder.uri)));
}),
vscode.workspace.onDidChangeConfiguration(async ({ affectsConfiguration }) => {
if (affectsConfiguration("objectscript.conn") || affectsConfiguration("intersystems.servers")) {
if (affectsConfiguration("intersystems.servers")) {
Expand Down Expand Up @@ -1545,7 +1552,23 @@ export async function activate(context: vscode.ExtensionContext): Promise<any> {
"vscode-objectscript.webSocketTerminal",
new WebSocketTerminalProfileProvider()
),
vscode.workspace.onDidChangeWorkspaceFolders((e) => {
vscode.workspace.onDidChangeWorkspaceFolders(async (e) => {
// Make sure we have a resolved connection spec for the targets of all added folders
const toCheck = new Map<string, vscode.Uri>();
e.added.map((workspaceFolder) => {
const uri = workspaceFolder.uri;
const { configName } = connectionTarget(uri);
toCheck.set(configName, uri);
});
for await (const oneToCheck of toCheck) {
const configName = oneToCheck[0];
const uri = oneToCheck[1];
const serverName = notIsfs(uri) ? config("conn", configName).server : configName;
await resolveConnectionSpec(serverName);
}
// await this so the next step can take advantage of the caching
await updateWebAndAbstractDocsCaches(e.added);
addWsServerRootFolderData(e.added);
// Show the proposed API prompt if required
proposedApiPrompt(proposed.length > 0, e.added);
// Warn about SystemMode
Expand Down
44 changes: 23 additions & 21 deletions src/providers/FileSystemProvider/FileSystemProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,7 @@ export class FileSystemProvider implements vscode.FileSystemProvider {
if (!api.active) throw vscode.FileSystemError.Unavailable("Server connection is inactive");
let entryPromise: Promise<Entry>;
let result: Entry;
const redirectedUri = redirectDotvscodeRoot(uri);
const redirectedUri = redirectDotvscodeRoot(uri, vscode.FileSystemError.FileNotFound(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
entryPromise = this._lookup(redirectedUri, true);
Expand Down Expand Up @@ -290,8 +290,8 @@ export class FileSystemProvider implements vscode.FileSystemProvider {
}

public async readDirectory(uri: vscode.Uri): Promise<[string, vscode.FileType][]> {
if (uri.path.includes(".vscode/")) {
throw vscode.FileSystemError.NoPermissions("Cannot read the /.vscode directory");
if (uri.path.includes(".vscode/") || uri.path.endsWith(".vscode")) {
throw new vscode.FileSystemError("Cannot read the /.vscode directory");
}
const parent = await this._lookupAsDirectory(uri);
const api = new AtelierAPI(uri);
Expand Down Expand Up @@ -406,7 +406,7 @@ export class FileSystemProvider implements vscode.FileSystemProvider {
}

public createDirectory(uri: vscode.Uri): void | Thenable<void> {
uri = redirectDotvscodeRoot(uri);
uri = redirectDotvscodeRoot(uri, new vscode.FileSystemError("Server does not have a /_vscode web application"));
const basename = path.posix.basename(uri.path);
const dirname = uri.with({ path: path.posix.dirname(uri.path) });
return this._lookupAsDirectory(dirname).then((parent) => {
Expand Down Expand Up @@ -435,9 +435,9 @@ export class FileSystemProvider implements vscode.FileSystemProvider {
overwrite: boolean;
}
): void | Thenable<void> {
uri = redirectDotvscodeRoot(uri);
uri = redirectDotvscodeRoot(uri, new vscode.FileSystemError("Server does not have a /_vscode web application"));
if (uri.path.startsWith("/.")) {
throw vscode.FileSystemError.NoPermissions("dot-folders not supported by server");
throw new vscode.FileSystemError("dot-folders are not supported by server");
}
const csp = isCSP(uri);
const fileName = isfsDocumentName(uri, csp);
Expand All @@ -462,10 +462,12 @@ export class FileSystemProvider implements vscode.FileSystemProvider {
[, clsname] = match;
}
if (clsname == "") {
throw new Error("Cannot save a malformed class");
throw new vscode.FileSystemError("Cannot save a malformed class");
}
if (fileName.slice(0, -4) != clsname) {
throw new Error("Cannot save an isfs class where the class name and file name do not match");
throw new vscode.FileSystemError(
"Cannot save an isfs class where the class name and file name do not match"
);
}
if (openLowCodeEditors.has(uri.toString())) {
// This class is open in a low-code editor, so any
Expand All @@ -474,7 +476,7 @@ export class FileSystemProvider implements vscode.FileSystemProvider {
}
// Check if the class is deployed
if (await isClassDeployed(fileName, api)) {
throw new Error("Cannot overwrite a deployed class");
throw new vscode.FileSystemError("Cannot overwrite a deployed class");
}
}
const contentBuffer = Buffer.from(content);
Expand Down Expand Up @@ -505,7 +507,7 @@ export class FileSystemProvider implements vscode.FileSystemProvider {
.catch((error) => {
// Throw all failures
const errorStr = stringifyError(error);
throw errorStr ? errorStr : vscode.FileSystemError.Unavailable(uri);
throw errorStr ? new vscode.FileSystemError(errorStr) : vscode.FileSystemError.Unavailable(uri);
});
},
(error) => {
Expand All @@ -529,7 +531,7 @@ export class FileSystemProvider implements vscode.FileSystemProvider {
.catch((error) => {
// Throw all failures
const errorStr = stringifyError(error);
throw errorStr ? errorStr : vscode.FileSystemError.Unavailable(uri);
throw errorStr ? new vscode.FileSystemError(errorStr) : vscode.FileSystemError.Unavailable(uri);
})
.then((data) => {
// New file has been written
Expand Down Expand Up @@ -639,7 +641,7 @@ export class FileSystemProvider implements vscode.FileSystemProvider {
}

public async delete(uri: vscode.Uri, options: { recursive: boolean }): Promise<void> {
uri = redirectDotvscodeRoot(uri);
uri = redirectDotvscodeRoot(uri, vscode.FileSystemError.FileNotFound(uri));
const { project } = isfsConfig(uri);
const csp = isCSP(uri);
const api = new AtelierAPI(uri);
Expand Down Expand Up @@ -724,13 +726,13 @@ export class FileSystemProvider implements vscode.FileSystemProvider {

public async rename(oldUri: vscode.Uri, newUri: vscode.Uri, options: { overwrite: boolean }): Promise<void> {
if (!oldUri.path.split("/").pop().includes(".")) {
throw vscode.FileSystemError.NoPermissions("Cannot rename a package/folder");
throw new vscode.FileSystemError("Cannot rename a package/folder");
}
if (oldUri.path.split(".").pop().toLowerCase() != newUri.path.split(".").pop().toLowerCase()) {
throw vscode.FileSystemError.NoPermissions("Cannot change a file's extension during rename");
throw new vscode.FileSystemError("Cannot change a file's extension during rename");
}
if (vscode.workspace.getWorkspaceFolder(oldUri) != vscode.workspace.getWorkspaceFolder(newUri)) {
throw vscode.FileSystemError.NoPermissions("Cannot rename a file across workspace folders");
throw new vscode.FileSystemError("Cannot rename a file across workspace folders");
}
// Check if the destination exists
let newFileStat: vscode.FileStat;
Expand Down Expand Up @@ -774,7 +776,7 @@ export class FileSystemProvider implements vscode.FileSystemProvider {
.catch((error) => {
// Throw all failures
const errorStr = stringifyError(error);
throw errorStr ? errorStr : vscode.FileSystemError.Unavailable(newUri);
throw errorStr ? new vscode.FileSystemError(errorStr) : vscode.FileSystemError.Unavailable(newUri);
})
.then(async (response) => {
// New file has been written
Expand Down Expand Up @@ -807,7 +809,7 @@ export class FileSystemProvider implements vscode.FileSystemProvider {
*/
public async compile(uri: vscode.Uri, file?: File, update?: boolean): Promise<void> {
if (!uri || uri.scheme != FILESYSTEM_SCHEMA) return;
uri = redirectDotvscodeRoot(uri);
uri = redirectDotvscodeRoot(uri, new vscode.FileSystemError("Server does not have a /_vscode web application"));
const compileList: string[] = [];
try {
const entry = file || (await this._lookup(uri, true));
Expand Down Expand Up @@ -958,9 +960,9 @@ export class FileSystemProvider implements vscode.FileSystemProvider {

// Fetch from server and cache it, optionally the passed cached copy if unchanged on server
private async _lookupAsFile(uri: vscode.Uri, cachedFile?: File): Promise<File> {
uri = redirectDotvscodeRoot(uri);
uri = redirectDotvscodeRoot(uri, vscode.FileSystemError.FileNotFound(uri));
if (uri.path.startsWith("/.")) {
throw vscode.FileSystemError.NoPermissions("dot-folders not supported by server");
throw new vscode.FileSystemError("dot-folders are not supported by server");
}
const csp = isCSP(uri);
const name = path.basename(uri.path);
Expand Down Expand Up @@ -992,13 +994,13 @@ export class FileSystemProvider implements vscode.FileSystemProvider {
throw error?.statusCode == 404
? vscode.FileSystemError.FileNotFound(uri)
: errorStr
? errorStr
? new vscode.FileSystemError(errorStr)
: vscode.FileSystemError.Unavailable(uri);
});
}

private async _lookupParentDirectory(uri: vscode.Uri): Promise<Directory> {
uri = redirectDotvscodeRoot(uri);
uri = redirectDotvscodeRoot(uri, new vscode.FileSystemError("Server does not have a /_vscode web application"));
return this._lookupAsDirectory(uri.with({ path: path.posix.dirname(uri.path) }));
}

Expand Down
Loading