Skip to content

Commit

Permalink
update from review
Browse files Browse the repository at this point in the history
  • Loading branch information
isabelizimm committed Oct 28, 2024
1 parent 9e27565 commit a80bf80
Show file tree
Hide file tree
Showing 6 changed files with 74 additions and 94 deletions.
12 changes: 1 addition & 11 deletions apps/vscode/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -1036,16 +1036,6 @@
"default": true,
"markdownDescription": "When using a venv or conda environment, prefer Quarto CLI installed with pip in that environment. This will override Quarto CLI in the `PATH`, but not an explicitly configured `#quarto.path#`."
},
"quarto.defaultEditor": {
"order": 11,
"type": "string",
"markdownDescription": "Default editor. Only applicable in Positron.",
"enum": [
"source",
"visual"
],
"default": "source"
},
"quarto.render.renderOnSave": {
"order": 12,
"scope": "window",
Expand Down Expand Up @@ -1392,7 +1382,7 @@
"@types/semver": "^7.3.13",
"@types/tmp": "^0.2.3",
"@types/uuid": "^9.0.0",
"@types/vscode": "1.94.0",
"@types/vscode": "1.75.0",
"@types/which": "^2.0.2",
"@typescript-eslint/eslint-plugin": "^5.45.0",
"@typescript-eslint/parser": "^5.45.0",
Expand Down
5 changes: 0 additions & 5 deletions apps/vscode/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ import { activateZotero } from "./providers/zotero/zotero";;
import { extensionHost } from "./host";
import { configuredQuartoPath } from "./core/quarto";
import { activateDenoConfig } from "./providers/deno-config";
import { defaultEditorOpener } from "./providers/editor/configurations"

export async function activate(context: vscode.ExtensionContext) {

Expand Down Expand Up @@ -126,10 +125,6 @@ export async function activate(context: vscode.ExtensionContext) {

// activate providers common to browser/node
activateCommon(context, host, engine, commands);

context.subscriptions.push(vscode.workspace.onDidChangeConfiguration(async () => {
defaultEditorOpener()
}));
}

export async function deactivate() {
Expand Down
2 changes: 1 addition & 1 deletion apps/vscode/src/providers/editor/configurations.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*
* configurations.ts
*
* Copyright (C) 2022 by Posit Software, PBC
* Copyright (C) 2024 by Posit Software, PBC
*
* Unless you have received this program directly from Posit Software pursuant
* to the terms of a commercial license agreement with Posit Software, then
Expand Down
139 changes: 67 additions & 72 deletions apps/vscode/src/providers/editor/editor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import {
Disposable,
CustomTextEditorProvider,
TextDocument,
TextEditor,
WebviewPanel,
CancellationToken,
Uri,
Expand Down Expand Up @@ -150,21 +151,15 @@ export class VisualEditorProvider implements CustomTextEditorProvider {
}));

// when the active editor changes see if we have a visual editor position for it
context.subscriptions.push(window.onDidChangeActiveTextEditor(debounce(async () => {
context.subscriptions.push(window.onDidChangeActiveTextEditor(debounce(async (editor: TextEditor | undefined) => {

// resolve if active editor is text or visual
const editor = window.activeTextEditor;
const visualEditor = VisualEditorProvider.activeEditor();
let document = editor?.document;

let document = editor?.document || visualEditor?.document;
if (!document) { return; }
if (editor && document && isQuartoDoc(document)) {
// determine what mode editor should be in
const config = defaultEditorOpener();
const editorMode = determineMode(document);

// determine what mode editor should be in
const config = defaultEditorOpener();
const editorMode = await determineMode(document);

if (editor && isQuartoDoc(document)) {

// check for switch (one shot)
const uri = document.uri.toString();
const isSwitch = this.visualEditorPendingSwitchToSource.has(uri);
Expand Down Expand Up @@ -196,7 +191,7 @@ export class VisualEditorProvider implements CustomTextEditorProvider {

// find the index
let cursorIndex = -1;
for (let i=(pos.locations.length-1); i>=0; i--) {
for (let i = (pos.locations.length - 1); i >= 0; i--) {
if (pos.pos >= pos.locations[i].pos) {
cursorIndex = i;
break;
Expand All @@ -208,11 +203,11 @@ export class VisualEditorProvider implements CustomTextEditorProvider {
source.getSourcePosLocations(document.getText()).then(locations => {
// map to source line
const selLine = (cursorIndex !== -1 && (locations.length > cursorIndex))
? (locations[cursorIndex] || locations[locations.length-1]).pos - 1
? (locations[cursorIndex] || locations[locations.length - 1]).pos - 1
: 0;

// navigate
const selRange = new Range(selLine, 0, selLine, 0);
const selRange = new Range(selLine, 0, selLine, 0);
editor.selection = new Selection(selRange.start, selRange.end);
editor.revealRange(selRange, TextEditorRevealType.InCenter);
});
Expand All @@ -239,11 +234,11 @@ export class VisualEditorProvider implements CustomTextEditorProvider {
this.visualEditorPendingSwitchToSource.add(document.uri.toString());
}

public static activeEditor(includeVisible?: boolean) : QuartoVisualEditor | undefined {
public static activeEditor(includeVisible?: boolean): QuartoVisualEditor | undefined {
const editor = this.visualEditors.activeEditor(includeVisible);
if (editor) {
return {
document: editor.document,
return {
document: editor.document,
hasFocus: async () => {
return await editor.editor.isFocused();
},
Expand All @@ -259,14 +254,14 @@ export class VisualEditorProvider implements CustomTextEditorProvider {
setBlockSelection: async (context, action) => {
await editor.editor.setBlockSelection(context, action);
},
viewColumn: editor.webviewPanel.viewColumn
viewColumn: editor.webviewPanel.viewColumn
};
} else {
return undefined;
}
}

public static editorForUri(uri: Uri) : TrackedEditor | undefined {
public static editorForUri(uri: Uri): TrackedEditor | undefined {
return this.visualEditors.editorForUri(uri);
}

Expand All @@ -275,23 +270,23 @@ export class VisualEditorProvider implements CustomTextEditorProvider {
}

constructor(private readonly context: ExtensionContext,
private readonly extensionHost: ExtensionHost,
private readonly quartoContext: QuartoContext,
private readonly lspRequest: JsonRpcRequestTransport,
private readonly engine: MarkdownEngine) {}
private readonly extensionHost: ExtensionHost,
private readonly quartoContext: QuartoContext,
private readonly lspRequest: JsonRpcRequestTransport,
private readonly engine: MarkdownEngine) { }



public async resolveCustomTextEditor(
document: TextDocument,
webviewPanel: WebviewPanel,
_token: CancellationToken
) {

// if the document is untitled then capture its contents (as vscode throws it on the floor
// if the document is untitled then capture its contents (as vscode throws it on the floor
// and we may need it to do a re-open)
const untitledContent =
(document.isUntitled &&
VisualEditorProvider.activeUntitled?.uri.toString() === document.uri.toString())
const untitledContent =
(document.isUntitled &&
VisualEditorProvider.activeUntitled?.uri.toString() === document.uri.toString())
? VisualEditorProvider.activeUntitled.content
: undefined;

Expand All @@ -307,11 +302,11 @@ export class VisualEditorProvider implements CustomTextEditorProvider {
const kLearnMore = "Learn More...";
const result = await window.showInformationMessage<string>(
"You are activating Quarto visual markdown editing mode.",
{
modal: true,
detail:
"Visual mode enables you to author using a familiar word processor style interface.\n\n" +
"Markdown code will be re-formatted using the Pandoc markdown writer."
{
modal: true,
detail:
"Visual mode enables you to author using a familiar word processor style interface.\n\n" +
"Markdown code will be re-formatted using the Pandoc markdown writer."
},
kUseVisualMode,
kLearnMore
Expand All @@ -327,7 +322,7 @@ export class VisualEditorProvider implements CustomTextEditorProvider {
this.context.globalState.update(kVisualModeConfirmed, true);
}
}

// some storage locations
const projectDir = document.isUntitled ? undefined : projectDirForDocument(document.fileName);
const workspaceDir = this.quartoContext.workspaceDir;
Expand All @@ -348,24 +343,24 @@ export class VisualEditorProvider implements CustomTextEditorProvider {
const xref = VisualEditorProvider.visualEditorPendingXRefNavigations.get(sourceUri);
VisualEditorProvider.visualEditorPendingXRefNavigations.delete(sourceUri);

// sync manager
// sync manager
const syncManager = editorSyncManager(
document,
client.editor,
this.lspRequest,
document,
client.editor,
this.lspRequest,
xref || sourcePos
);

// editor container implementation
const host: VSCodeVisualEditorHost = {

// editor is querying for context
getHostContext: async () : Promise<HostContext> => {
getHostContext: async (): Promise<HostContext> => {
return {
documentPath: document.isUntitled ? null : document.fileName,
projectDir,
resourceDir: document.isUntitled
? (workspaceDir || process.cwd())
resourceDir: document.isUntitled
? (workspaceDir || process.cwd())
: path.dirname(document.fileName),
isWindowsDesktop: isWindows(),
executableLanguages: this.extensionHost.executableLanguages(true, document, this.engine)
Expand Down Expand Up @@ -472,9 +467,9 @@ export class VisualEditorProvider implements CustomTextEditorProvider {

// setup server on webview iframe
disposables.push(visualEditorServer(
webviewPanel,
this.lspRequest,
host,
webviewPanel,
this.lspRequest,
host,
prefsServer,
vscodeCodeViewServer(this.engine, document, this.lspRequest)
));
Expand All @@ -484,7 +479,7 @@ export class VisualEditorProvider implements CustomTextEditorProvider {

// monitor image file changes
const kImagePattern = '**/*.{png,svg,jpg,jpeg}';
const globPattern : GlobPattern = docDir
const globPattern: GlobPattern = docDir
? { baseUri: Uri.file(docDir), base: docDir, pattern: kImagePattern }
: kImagePattern;
const watcher = workspace.createFileSystemWatcher(globPattern);
Expand All @@ -497,13 +492,13 @@ export class VisualEditorProvider implements CustomTextEditorProvider {
watcher.onDidDelete(onChange);

// load editor webview (include current doc path in localResourceRoots)
webviewPanel.webview.options = {
webviewPanel.webview.options = {
localResourceRoots: [
this.context.extensionUri,
this.context.extensionUri,
...(workspace.workspaceFolders ? workspace.workspaceFolders.map(folder => folder.uri) : []),
...(docDir ? [Uri.file(docDir)] : [])
],
enableScripts: true
enableScripts: true
};
webviewPanel.webview.html = this.getHtmlForWebview(webviewPanel.webview);

Expand All @@ -516,7 +511,7 @@ export class VisualEditorProvider implements CustomTextEditorProvider {
disposable.dispose();
}
});

}

private editorAssetUri(webview: Webview, file: string) {
Expand All @@ -533,7 +528,7 @@ export class VisualEditorProvider implements CustomTextEditorProvider {
* Get the static html used for the editor webviews.
*/
private getHtmlForWebview(webview: Webview): string {

const scriptUri = this.editorAssetUri(webview, "index.js");
const stylesUri = this.editorAssetUri(webview, "style.css");
const codiconsUri = this.extensionResourceUrl(webview, [
Expand Down Expand Up @@ -583,7 +578,7 @@ export class VisualEditorProvider implements CustomTextEditorProvider {
}

async function navigateToFile(baseDoc: TextDocument, file: string, xref?: XRef) {

const docDir = path.dirname(baseDoc.uri.fsPath);
const filePath = path.normalize(path.isAbsolute(file) ? file : path.join(docDir, file));
const uri = Uri.file(filePath);
Expand All @@ -605,11 +600,11 @@ async function navigateToFile(baseDoc: TextDocument, file: string, xref?: XRef)
} else {
await openWith(VisualEditorProvider.viewType);
}

} else if (ext === ".ipynb") {

await openWith("jupyter-notebook");

} else {

const doc = await workspace.openTextDocument(uri);
Expand Down Expand Up @@ -638,13 +633,13 @@ interface VisualEditorTracker {
activeEditor: (includeVisible?: boolean) => TrackedEditor | undefined;
}

function visualEditorTracker() : VisualEditorTracker {
function visualEditorTracker(): VisualEditorTracker {

const activeEditors = new Array<TrackedEditor>();

return {
track: (document: TextDocument, webviewPanel: WebviewPanel, editor: VSCodeVisualEditor) : Disposable => {
activeEditors.push({document, webviewPanel, editor});
track: (document: TextDocument, webviewPanel: WebviewPanel, editor: VSCodeVisualEditor): Disposable => {
activeEditors.push({ document, webviewPanel, editor });
return {
dispose: () => {
const idx = activeEditors.findIndex(editor => editor.webviewPanel === webviewPanel);
Expand All @@ -661,20 +656,20 @@ function visualEditorTracker() : VisualEditorTracker {
return activeEditors.find(editor => {
try {
return editor.webviewPanel.active || (includeVisible && editor.webviewPanel.visible);
} catch(err) {
} catch (err) {
// we've seen activeEditors hold on to references to disposed editors (can't on the
// surface see how this would occur as we subscribe to dispose, but as an insurance
// policy let's eat any exception that occurs, since a single zombie webviewPanel
// would prevent rendering of other panels
return false;
}
}

});
}
};
}

function focusTracker(webviewPanel: WebviewPanel, editor: VSCodeVisualEditor) : Disposable {
function focusTracker(webviewPanel: WebviewPanel, editor: VSCodeVisualEditor): Disposable {

let hasFocus = false;
let cancelled = false;
Expand All @@ -685,18 +680,18 @@ function focusTracker(webviewPanel: WebviewPanel, editor: VSCodeVisualEditor) :
editor.focus();
};

// if we are focused when the window loses focus then restore on re-focus
let reFocus = false;
const evWindow = window.onDidChangeWindowState(async (event) => {
if (!event.focused && hasFocus) {
reFocus = true;
} else if (event.focused && reFocus) {
setTimeout(async () => {
// if we are focused when the window loses focus then restore on re-focus
let reFocus = false;
const evWindow = window.onDidChangeWindowState(async (event) => {
if (!event.focused && hasFocus) {
reFocus = true;
} else if (event.focused && reFocus) {
setTimeout(async () => {
await focusEditor();
reFocus = false;
}, 200);
}
});
}, 200);
}
});

// periodically check for focus
const timer = setInterval(async () => {
Expand Down
2 changes: 1 addition & 1 deletion apps/vscode/src/providers/editor/toggle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ export function modeFromQuartoYaml(doc: TextDocument): string | undefined {
for (const metadataFile of metadataFiles) {
const yamlText = quarto.yamlFromMetadataFile(metadataFile);
if (yamlText?.editor === "source") {
return "textEditor"
return "default"
}
if (yamlText?.editor === "visual") {
return VisualEditorProvider.viewType;
Expand Down
Loading

0 comments on commit a80bf80

Please sign in to comment.