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
19 changes: 12 additions & 7 deletions apps/lsp/src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -158,22 +158,27 @@ export class ConfigurationManager extends Disposable {

public async update() {
this._logger.logTrace('Sending \'configuration\' request');
const settings = await this.connection_.workspace.getConfiguration();
// Request only the specific sections we need to avoid warnings about
// language-scoped settings like [markdown], [python], etc.
const [workbench, quarto] = await this.connection_.workspace.getConfiguration([
{ section: 'workbench' },
{ section: 'quarto' }
]);

this._settings = {
...defaultSettings(),
workbench: {
colorTheme: settings.workbench.colorTheme
colorTheme: workbench?.colorTheme ?? this._settings.workbench.colorTheme
},
quarto: {
logLevel: Logger.parseLogLevel(settings.quarto.server.logLevel),
path: settings.quarto.path,
logLevel: Logger.parseLogLevel(quarto?.server?.logLevel),
path: quarto?.path ?? this._settings.quarto.path,
mathjax: {
scale: settings.quarto.mathjax.scale,
extensions: settings.quarto.mathjax.extensions
scale: quarto?.mathjax?.scale ?? this._settings.quarto.mathjax.scale,
extensions: quarto?.mathjax?.extensions ?? this._settings.quarto.mathjax.extensions
},
symbols: {
exportToWorkspace: settings.quarto.symbols.exportToWorkspace
exportToWorkspace: quarto?.symbols?.exportToWorkspace ?? this._settings.quarto.symbols.exportToWorkspace
Comment on lines +171 to +181
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice, more defensive (less error possibilities and risk of things being undefined) and probably more correct.

}
}
};
Expand Down
53 changes: 45 additions & 8 deletions apps/vscode/src/core/quarto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,31 +18,50 @@ import * as fs from "node:fs";

import { window, env, workspace, Uri } from "vscode";
import { tryAcquirePositronApi } from "@posit-dev/positron";
import { QuartoContext } from "quarto-core";
import { QuartoContext, QuartoSource } from "quarto-core";
import { activePythonInterpreter, pythonIsCondaEnv, pythonIsVenv } from "./python";
import { isWindows } from "./platform";


import semver from "semver";


export async function configuredQuartoPath() {
/**
* Result of configuredQuartoPath including the path and source.
*/
export interface ConfiguredQuartoPathResult {
path: string;
source: QuartoSource;
}

/**
* Searches for Quarto in VS Code-specific locations (settings, Positron bundled, pip/venv).
*
* @param logger Optional logger for verbose output
* @returns The path and source if found, undefined otherwise
*/
export async function configuredQuartoPath(
logger?: (msg: string) => void
): Promise<ConfiguredQuartoPathResult | undefined> {

const config = workspace.getConfiguration("quarto");

// explicitly configured trumps everything
const quartoPath = config.get("path") as string | undefined;
if (quartoPath) {
return quartoPath;
logger?.(` Checking quarto.path setting: ${quartoPath}`);
return { path: quartoPath, source: "setting" };
} else {
logger?.(" Checking quarto.path setting: not configured");
}

// check if we should use bundled Quarto in Positron
const useBundledQuarto = config.get("useBundledQuartoInPositron", false); // Default is now false
if (useBundledQuarto) {
// Check if we're in Positron
const isPositron = tryAcquirePositronApi();
const isPositron = tryAcquirePositronApi();

if (useBundledQuarto) {
if (isPositron) {
logger?.(" Checking Positron bundled Quarto: enabled");
// Use path relative to the application root for Positron's bundled Quarto
const rootPath = env.appRoot; // Use vscode.env.appRoot as the application root path
const positronQuartoPath = path.join(
Expand All @@ -53,9 +72,11 @@ export async function configuredQuartoPath() {
);

if (fs.existsSync(positronQuartoPath)) {
return positronQuartoPath;
logger?.(` Found Positron bundled Quarto at ${positronQuartoPath}`);
return { path: positronQuartoPath, source: "positron-bundled" };
} else {
// Log error when bundled Quarto can't be found
logger?.(` Positron bundled Quarto not found at ${positronQuartoPath}`);
console.error(
`useBundledQuartoInPositron is enabled but bundled Quarto not found at expected path: ${positronQuartoPath}. ` +
`Verify Quarto is bundled in the Positron installation.`
Expand All @@ -65,24 +86,40 @@ export async function configuredQuartoPath() {
"Unable to find bundled Quarto in Positron; falling back to system installation"
);
}
} else {
logger?.(" Not running in Positron, skipping bundled Quarto check");
}
} else {
logger?.(` Checking Positron bundled Quarto: disabled (useBundledQuartoInPositron = false)`);
}

// if we can use pip quarto then look for it within the currently python (if its a venv/condaenv)
const usePipQuarto = config.get("usePipQuarto", true);
if (usePipQuarto) {
logger?.(" Checking pip-installed Quarto in Python venv/conda...");
const python = await activePythonInterpreter();
if (python) {
if (pythonIsVenv(python) || pythonIsCondaEnv(python)) {
// check if there is a quarto in the parent directory
const binDir = path.dirname(python);
const quartoPath = path.join(binDir, isWindows() ? "quarto.exe" : "quarto");
if (fs.existsSync(quartoPath)) {
return quartoPath;
logger?.(` Found pip-installed Quarto at ${quartoPath}`);
return { path: quartoPath, source: "pip-venv" };
} else {
logger?.(` No Quarto found in Python environment at ${binDir}`);
}
} else {
logger?.(" Active Python is not in a venv or conda environment");
}
} else {
logger?.(" No active Python interpreter found");
}
} else {
logger?.(" Checking pip-installed Quarto: disabled (usePipQuarto = false)");
}

return undefined;
}


Expand Down
21 changes: 17 additions & 4 deletions apps/vscode/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ import { activateEditor } from "./providers/editor/editor";
import { activateCopyFiles } from "./providers/copyfiles";
import { activateZotero } from "./providers/zotero/zotero";
import { extensionHost } from "./host";
import { initQuartoContext } from "quarto-core";
import { initQuartoContext, getSourceDescription } from "quarto-core";
import { configuredQuartoPath } from "./core/quarto";
import { activateDenoConfig } from "./providers/deno-config";
import { textFormattingCommands } from "./providers/text-format";
Expand Down Expand Up @@ -64,17 +64,30 @@ export async function activate(context: vscode.ExtensionContext) {
const commands = cellCommands(host, engine);

// get quarto context (some features conditional on it)
const quartoPath = await configuredQuartoPath();
// Create a logger function for verbose discovery output
const discoveryLogger = (msg: string) => outputChannel.info(msg);

outputChannel.info("Searching for Quarto CLI...");
const quartoPathResult = await configuredQuartoPath(discoveryLogger);
const workspaceFolder = vscode.workspace.workspaceFolders?.length
? vscode.workspace.workspaceFolders[0].uri.fsPath
: undefined;
const quartoContext = initQuartoContext(
quartoPath,
quartoPathResult?.path,
workspaceFolder,
// Look for quarto in the app root; this is where Positron installs it
[path.join(vscode.env.appRoot, "quarto", "bin")],
vscode.window.showWarningMessage
vscode.window.showWarningMessage,
{ logger: discoveryLogger, source: quartoPathResult?.source }
);

// Log the final discovery result
if (quartoContext.available) {
const sourceDescription = getSourceDescription(quartoContext.source);
outputChannel.info(`Using Quarto ${quartoContext.version} from ${quartoContext.binPath}${sourceDescription}`);
} else {
outputChannel.info("Quarto CLI not found. Some features will be unavailable.");
}
if (quartoContext.available) {

// enable commands conditional on quarto installation
Expand Down
2 changes: 1 addition & 1 deletion apps/vscode/src/providers/copyfiles/filename.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ export async function getNewFileName(document: vscode.TextDocument, file: vscode

function getDesiredNewFilePath(document: vscode.TextDocument, file: vscode.DataTransferFile): vscode.Uri {
const docUri = getParentDocumentUri(document);
const config = vscode.workspace.getConfiguration('markdown').get<Record<string, string>>('experimental.copyFiles.destination') ?? {};
const config = vscode.workspace.getConfiguration('markdown', docUri).get<Record<string, string>>('experimental.copyFiles.destination') ?? {};
for (const [rawGlob, rawDest] of Object.entries(config)) {
for (const glob of parseGlob(rawGlob)) {
if (picomatch.isMatch(docUri.path, glob)) {
Expand Down
2 changes: 1 addition & 1 deletion apps/vscode/src/providers/deno-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export function activateDenoConfig(context: ExtensionContext, engine: MarkdownEn
if (extensions.getExtension("denoland.vscode-deno")) {
const ensureDenoConfig = async (doc: TextDocument) => {
if (isQuartoDoc(doc)) {
const config = workspace.getConfiguration();
const config = workspace.getConfiguration(undefined, doc.uri);
const inspectDenoEnable = config.inspect("deno.enable");
if (
!inspectDenoEnable?.globalValue &&
Expand Down
Loading