Skip to content
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

add initial idea for flares #2680

Draft
wants to merge 10 commits into
base: dev
Choose a base branch
from
Next Next commit
add initial idea for flares
  • Loading branch information
timothypratley committed Dec 26, 2024
commit 91496acb9a8a7c354385f4e8e8c285e501c754b7
7 changes: 7 additions & 0 deletions src/evaluate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import * as output from './results-output/output';
import * as inspector from './providers/inspector';
import { resultAsComment } from './util/string-result';
import { highlight } from './highlight/src/extension';
import * as flareHandler from './flare-handler';

let inspectorDataProvider: inspector.InspectorDataProvider;

Expand Down Expand Up @@ -139,6 +140,8 @@ async function evaluateCodeUpdatingUI(

result = value;

flareHandler.inspect(value);

if (showResult) {
inspectorDataProvider.addItem(value, false, `[${session.replType}] ${ns}`);
output.appendClojureEval(value, { ns, replSessionType: session.replType }, async () => {
Expand Down Expand Up @@ -732,6 +735,10 @@ async function evaluateInOutputWindow(code: string, sessionType: string, ns: str
}
}

function inspect(value){

}

export default {
interruptAllEvaluations,
loadDocument,
Expand Down
64 changes: 64 additions & 0 deletions src/flare-handler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import * as vscode from 'vscode';
import * as webview from './webview';

let evalFn: (code: any) => void;
export function setEvalFn(fn: typeof evalFn) {
evalFn = fn;
}

function isFlare(value: any): boolean {
return (
typeof value === 'object' &&
value !== null &&
Object.keys(value).length === 1 &&
value.hasOwnProperty('calva/flare')
);
}

function getFlareRequest(flare: Record<string, any>): any {
return Object.values(flare)[0];
}

type InfoRequest = { type: 'info'; message: string; items?: string[]; then?: any };
type WarnRequest = { type: 'warn'; message: string; items?: string[] };
type ErrorRequest = { type: 'error'; message: string; items?: string[] };
type WebviewRequest = { type: 'webview'; title?: string; html?: string; url?: string; key?: string; column?: vscode.ViewColumn; opts?: any};
type DefaultRequest = { type: 'default'; [key: string]: any };

type ActRequest = InfoRequest | WarnRequest | ErrorRequest | WebviewRequest | DefaultRequest;

const actHandlers: Record<string, (request: ActRequest) => void> = {
default: (request: DefaultRequest) => {
vscode.window.showErrorMessage(`Unknown flare request type: ${JSON.stringify(request.type)}`);
},
info: ({ message, items = [], then }: InfoRequest) => {
const p = vscode.window.showInformationMessage(message, ...items);
if (then) {
p.then((selected) => {
evalFn?.([['resolve', then], selected]);
});
}
},
warn: ({ message, items = [] }: WarnRequest) => {
vscode.window.showWarningMessage(message, ...items);
},
error: ({ message, items = [] }: ErrorRequest) => {
vscode.window.showErrorMessage(message, ...items);
},
webview: (request: WebviewRequest) => {
webview.show(request);
}
};

function act(request: ActRequest): void {
const handler = actHandlers[request.type] || actHandlers.default;
handler(request);
}

export function inspect(x: any): any {
if (isFlare(x)) {
console.log('FLARE');
act(getFlareRequest(x));
}
return x;
}
82 changes: 82 additions & 0 deletions src/webview.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import * as vscode from 'vscode';

const defaultOpts = {
enableScripts: true
};

function insertPanel(state: { webviews: Record<string, vscode.WebviewPanel> }, key: string, panel: vscode.WebviewPanel): void {
state.webviews[key] = panel;
}

function deleteWebviewPanel(state: { webviews: Record<string, vscode.WebviewPanel> }, key: string): void {
delete state.webviews[key];
}

function selectWebviewPanel(state: { webviews: Record<string, vscode.WebviewPanel> }, key: string): vscode.WebviewPanel | undefined {
return state.webviews[key];
}

function setHtml(panel: vscode.WebviewPanel, title: string, html: string): vscode.WebviewPanel {
if (panel.title !== title) {
panel.title = title;
}
if (panel.webview.html !== html) {
panel.webview.html = html;
}
panel.reveal();
return panel;
}

function urlInIframe(uri: string): string {
return `<!DOCTYPE html>
<html>
<head>
<style type="text/css">
body, html {
margin: 0; padding: 0; height: 100%; overflow: hidden;
}
#content {
position: absolute; left: 0; right: 0; bottom: 0; top: 0px;
}
</style>
</head>
<body>
<iframe src="${uri}" style="width:100%; height:100%; border:none;"></iframe>
</body>
</html>`;
}

export function show({
title = "Webview",
html,
url,
key,
column = vscode.ViewColumn.Beside,
opts = defaultOpts
}: {
title?: string;
html?: string;
url?: string;
key?: string;
column?: vscode.ViewColumn;
opts?: typeof defaultOpts;
}): vscode.WebviewPanel {
const finalHtml = url ? urlInIframe(url) : html || '';
const appState = db.getAppState();
if (key) {
const existingPanel = selectWebviewPanel(appState, key);
if (existingPanel) {
return setHtml(existingPanel, title, finalHtml);
}
}

const panel = vscode.window.createWebviewPanel("calva-webview", title, column, opts);
setHtml(panel, title, finalHtml);

if (key) {
insertPanel(appState, key, panel);
panel.onDidDispose(() => deleteWebviewPanel(appState, key));
}

return panel;
}