Skip to content

Fix: Reopening editors #48

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

Closed
wants to merge 6 commits into from
Closed
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
70 changes: 40 additions & 30 deletions src/commands/showPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,48 +33,58 @@ export async function showPanel(
retainContextWhenHidden: true,
},
);
// Get a reference to the active editor (before the focus is switched to our newly created webview)
// firstEditor = vscode.window.activeTextEditor!;

messageHandler.panel.webview.onDidReceiveMessage(
(message: MessageType) => messageHandler.handleMessage(context, message),
undefined,
context.subscriptions,
);
}

const iframeUrl = new URL(route ?? "/playground", config.frontendBaseUrl)
.href;
messageHandler.panel.onDidDispose(() => {
console.log("Panel disposed, clearing message handler panel");
messageHandler.panel = null;
});

const iframeUrl = new URL(route ?? "/playground", config.frontendBaseUrl)
.href;

setWebviewContent(
messageHandler.panel,
context,
// NOTE: This is not React code, but our FakeReact!
<div
// Account for some unexplainable margin
// @ts-expect-error: Our FakeReact doesn't modify the style attribute
style="width: 100%; height: calc(100vh - 10px)"
>
<iframe
id={FRONTEND_ELEMENT_ID}
src={iframeUrl}
width="100%"
height="100%"
// @ts-ignore
frameborder="0"
allowfullscreen
></iframe>
</div>,
);
setWebviewContent(
messageHandler.panel,
context,
// NOTE: This is not React code, but our FakeReact!
<div
// Account for some unexplainable margin
// @ts-expect-error: Our FakeReact doesn't modify the style attribute
style="width: 100%; height: calc(100vh - 10px)"
>
<iframe
id={FRONTEND_ELEMENT_ID}
src={iframeUrl}
width="100%"
height="100%"
// @ts-ignore
frameborder="0"
allowfullscreen
></iframe>
</div>,
);

messageHandler.panel.iconPath = SOURCE_ACADEMY_ICON_URI;
messageHandler.panel.iconPath = SOURCE_ACADEMY_ICON_URI;
}
}

export async function sendToFrontendWrapped(message: MessageType) {
sendToFrontend(messageHandler.panel, message);
// TODO: This returning of status code shouldn't be necessary after refactor
export function sendToFrontendWrapped(message: MessageType): boolean {
if (!messageHandler.panel) {
console.error("ERROR: panel is not set");
return false;
}
sendToFrontend(messageHandler.panel, message);
return true;
try {
sendToFrontend(messageHandler.panel, message);
return true;
} catch (err) {
console.error("Failed to send message to webview", err);
messageHandler.panel = null;
return false;
}
}
33 changes: 31 additions & 2 deletions src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,22 +14,51 @@ export let client: LanguageClient;

export let SOURCE_ACADEMY_ICON_URI: vscode.Uri;

// Shared output channel for logging diagnostic messages
let outputChannel: vscode.OutputChannel;

// This method is called when your extension is activated
// Your extension is activated the very first time the command is executed
export function activate(context: vscode.ExtensionContext) {
// Initialise output channel early so all parts can use it
outputChannel = vscode.window.createOutputChannel("Source Academy");
context.subscriptions.push(outputChannel);

// Validate user-provided settings up-front
try {
new URL(config.frontendBaseUrl);
} catch {
vscode.window.showErrorMessage(
"Source Academy: Invalid Frontend URL in settings (source-academy.frontendBaseUrl).",
);
}
setupTreeView(context);
registerAllCommands(context);

context.subscriptions.push(setupStatusBar(context));

client = activateLspClient(context);
try {
client = activateLspClient(context);
} catch (e: any) {
vscode.window.showErrorMessage(
"Source Academy: Failed to start language server – " + (e?.message ?? e),
);
outputChannel.appendLine(String(e?.stack ?? e));
throw e; // rethrow so VS Code knows activation failed
}

// const info = {
// "file:///home/heyzec/.sourceacademy/playground_1.js": { chapter: 4 },
// };
const info = context.globalState.get("info") ?? {};

client.sendRequest("source/publishInfo", info);
try {
client.sendRequest("source/publishInfo", info);
} catch (e: any) {
outputChannel.appendLine(
"Error sending initial info to language server: " + String(e),
);
}

SOURCE_ACADEMY_ICON_URI = vscode.Uri.joinPath(
context.extensionUri,
Expand Down
10 changes: 5 additions & 5 deletions src/utils/messageHandler.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ export class MessageHandler {
this.mcqPanel = vscode.window.createWebviewPanel(
"mcq-question-panel",
`MCQ`,
vscode.ViewColumn.One,
vscode.ViewColumn.Two,
{ enableScripts: true, retainContextWhenHidden: true },
);

Expand Down Expand Up @@ -88,7 +88,7 @@ export class MessageHandler {
{ReactDOMServer.renderToString(activePanel)}
</div>,
);
this.mcqPanel.reveal(vscode.ViewColumn.One);
this.mcqPanel.reveal(vscode.ViewColumn.Two);

break;
}
Expand Down Expand Up @@ -173,9 +173,9 @@ export class MessageHandler {
this.panel?.reveal(vscode.ViewColumn.Two);
}
break;
case MessageTypeNames.LoginWithBrowser:
const { route } = message;
vscode.env.openExternal(vscode.Uri.parse(route));
case MessageTypeNames.LoginWithBrowser:
const { route } = message;
vscode.env.openExternal(vscode.Uri.parse(route));
}
console.log(`${Date.now()} Finish handleMessage: ${message.type}`);
}
Expand Down
11 changes: 2 additions & 9 deletions src/webview/components/SourceAcademy.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* It simply relays messages between the VSC Extension context and the Frontend iframe context.
*/
//
import React, { useEffect } from "react";
import React, { useEffect, useState, useCallback } from "react";
import Messages, { MessageType, MessageTypeNames } from "../../utils/messages";
import { FRONTEND_ELEMENT_ID } from "../../constants";

Expand Down Expand Up @@ -32,6 +32,7 @@ function initialListener(event: MessageEvent) {
event.origin === message.frontendOrigin
) {
frontendBaseUrl = event.origin;

relayToExtension(message);
window.addEventListener("message", messageListener);
return;
Expand All @@ -51,14 +52,6 @@ function messageListener(event: MessageEvent) {
}

const SourceAcademy: React.FC = () => {
useEffect(() => {
window.addEventListener("message", initialListener);
return () => {
window.removeEventListener("message", initialListener);
window.removeEventListener("message", messageListener);
};
}, []);

useEffect(() => {
// TODO: Hacky way to update mcq panel, standard onClick handlers don't work
const highlightSelection = (
Expand Down