Skip to content
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
14 changes: 14 additions & 0 deletions integrations/code/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -492,6 +492,20 @@
"type": "string",
"default": "",
"description": "Path to Zensical Studio, optional"
},
"zensical.studio.projects.include": {
"type": "array",
"items": { "type": "string" },
"default": [],
"scope": "resource",
"description": "Project-root globs relative to each workspace folder. Empty includes all discovered projects."
},
"zensical.studio.projects.exclude": {
"type": "array",
"items": { "type": "string" },
"default": [],
"scope": "resource",
"description": "Project-root globs relative to each workspace folder. Excludes take precedence over includes."
}
}
}
Expand Down
3 changes: 2 additions & 1 deletion integrations/code/src/extension/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import {

import type { Context } from "./context";
import type { Studio } from "./studio";
import { projectSelections } from "./project";

/* ----------------------------------------------------------------------------
* Functions
Expand Down Expand Up @@ -82,7 +83,7 @@ export function createLanguageClient(
{ scheme: "file", language: "yaml", pattern: "**/mkdocs.yaml" },
],
outputChannel: context.getOutput(),
initializationOptions: { token: studio.token },
initializationOptions: { token: studio.token, ...projectSelections() },
errorHandler: {
error: (_error, _message, count) => {
if (typeof count === "number" && count <= 3) {
Expand Down
63 changes: 62 additions & 1 deletion integrations/code/src/extension/project.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,32 @@ interface DocumentState {
* Functions
* ------------------------------------------------------------------------- */

/**
* Project-root patterns for every VS Code workspace folder.
*
* @returns Resource-scoped selections for server initialization and reloads
*/
export function projectSelections(): {
projects: Array<{
workspaceUri: string;
include: string[];
exclude: string[];
}>;
} {
return {
projects: (vscode.workspace.workspaceFolders ?? []).map((folder) => {
const settings = vscode.workspace.getConfiguration(
"zensical.studio.projects", folder.uri,
);
return {
workspaceUri: folder.uri.toString(),
include: settings.get<string[]>("include", []),
exclude: settings.get<string[]>("exclude", []),
};
}),
};
}

/**
* Activate project-aware Markdown tagging.
*
Expand All @@ -72,6 +98,20 @@ export async function activateProjectMarkdown(
const openDocuments = new Map<string, DocumentState>();
const changingLanguage = new Set<string>();
const roots = new Map<string, string[]>();
let projectUpdates = Promise.resolve();
let projectUpdateQueued = false;

// Refresh project selections in Studio when the configuration changes
const refreshProjects = (): void => {
if (projectUpdateQueued) return;
projectUpdateQueued = true;
projectUpdates = projectUpdates.then(async () => {
projectUpdateQueued = false;
await client.sendRequest("zensical/workspace/projects", projectSelections());
}).catch((error) => {
context.log(`Failed to update project selection: ${String(error)}`);
});
};

// Refresh managed Markdown roots for all workspace folders
const refreshScopes = async (): Promise<void> => {
Expand Down Expand Up @@ -118,6 +158,11 @@ export async function activateProjectMarkdown(

// Register event listeners for workspace changes and document lifecycle
const subscriptions: Disposable[] = [
vscode.workspace.onDidChangeConfiguration((event) => {
if (event.affectsConfiguration("zensical.studio.projects")) {
refreshProjects();
}
}),
client.onNotification("zensical/workspace/scopesChanged", () => {
void refreshScopes();
}),
Expand Down Expand Up @@ -210,9 +255,25 @@ async function tagDocument(
return;
}

// Skip documents that are not inside a managed root
// Restore documents Studio tagged before their project was excluded.
const folderRoots = roots.get(folder.uri.toString()) ?? [];
if (!isManaged(document.uri, folderRoots)) {
const key = document.uri.toString();
const state = openDocuments.get(key);
if (
state?.automaticallyTagged && !state.userOverride &&
!changingLanguage.has(key) &&
document.languageId === "python-markdown"
) {
changingLanguage.add(key);
try {
await vscode.languages.setTextDocumentLanguage(document, "markdown");
state.languageId = "markdown";
state.automaticallyTagged = false;
} finally {
changingLanguage.delete(key);
}
}
return;
}

Expand Down
Loading