add ctrlk webview provider

This commit is contained in:
Andrew 2024-10-25 22:10:22 -07:00
parent f56772a07a
commit 8f83b063f1
6 changed files with 88 additions and 36 deletions

View file

@ -3,23 +3,7 @@ import { DisplayChangesProvider } from './DisplayChangesProvider';
import { BaseDiffArea, ChatThreads, MessageFromSidebar, MessageToSidebar } from '../common/shared_types';
import { SidebarWebviewProvider } from './providers/SidebarWebviewProvider';
import { v4 as uuidv4 } from 'uuid'
// this comes from vscode.proposed.editorInsets.d.ts
declare module 'vscode' {
export interface WebviewEditorInset {
readonly editor: vscode.TextEditor;
readonly line: number;
readonly height: number;
readonly webview: vscode.Webview;
readonly onDidDispose: Event<void>;
dispose(): void;
}
export namespace window {
export function createWebviewTextEditorInset(editor: vscode.TextEditor, line: number, height: number, options?: vscode.WebviewOptions): WebviewEditorInset;
}
}
import { CtrlKWebviewProvider } from './providers/CtrlKWebviewProvider';
const readFileContentOfUri = async (uri: vscode.Uri) => {
return Buffer.from(await vscode.workspace.fs.readFile(uri)).toString('utf8')
@ -38,6 +22,8 @@ export function activate(context: vscode.ExtensionContext) {
vscode.window.registerWebviewViewProvider(SidebarWebviewProvider.viewId, sidebarWebviewProvider, { webviewOptions: { retainContextWhenHidden: true } })
);
// 1.5
const ctrlKWebviewProvider = new CtrlKWebviewProvider(context)
// 2. ctrl+l
@ -81,7 +67,7 @@ export function activate(context: vscode.ExtensionContext) {
const filePath = editor.document.uri;
// send message to the webview (Sidebar.tsx)
sidebarWebviewProvider.webview.then(webview => webview.postMessage({ type: 'ctrl+k', selection: { selectionStr, selectionRange, filePath } } satisfies MessageToSidebar));
ctrlKWebviewProvider.onPressCtrlK()
})
);

View file

@ -11,7 +11,7 @@ function generateNonce() {
// call this when you have access to the webview to set its html
export const updateWebviewHTML = (webview: vscode.Webview, extensionUri: vscode.Uri, { jsOutLocation, cssOutLocation }: { jsOutLocation: string, cssOutLocation: string }) => {
export const updateWebviewHTML = (webview: vscode.Webview, extensionUri: vscode.Uri, { jsOutLocation, cssOutLocation }: { jsOutLocation: string, cssOutLocation: string }, props?: object) => {
// 'dist/sidebar/index.js'
// 'dist/sidebar/styles.css'
@ -32,8 +32,7 @@ export const updateWebviewHTML = (webview: vscode.Webview, extensionUri: vscode.
<link href="${stylesUri}" rel="stylesheet">
</head>
<body>
<div id="root"></div>
<div id="ctrlkroot"></div>
<div id="root" ${props ? `data-void-props="${encodeURIComponent(JSON.stringify(props))}"` : ''}></div>
<script nonce="${nonce}" src="${scriptUri}"></script>
</body>
</html>`;

View file

@ -1,19 +1,57 @@
// renders the code from `src/sidebar`
import * as vscode from 'vscode';
import { updateWebviewHTML as _updateWebviewHTML } from '../extensionLib/updateWebviewHTML';
import { updateWebviewHTML as _updateWebviewHTML, updateWebviewHTML } from '../extensionLib/updateWebviewHTML';
// this comes from vscode.proposed.editorInsets.d.ts
declare module 'vscode' {
export interface WebviewEditorInset {
readonly editor: vscode.TextEditor;
readonly line: number;
readonly height: number;
readonly webview: vscode.Webview;
readonly onDidDispose: Event<void>;
dispose(): void;
}
export namespace window {
export function createWebviewTextEditorInset(editor: vscode.TextEditor, line: number, height: number, options?: vscode.WebviewOptions): WebviewEditorInset;
}
}
export class CtrlKWebviewProvider {
private readonly _extensionUri: vscode.Uri
private _idPool = 0
constructor(context: vscode.ExtensionContext) {
this._extensionUri = context.extensionUri
}
onPressCtrlK() {
// TODO if currently selecting a ctrl k element, just focus it and do nothing
const inset = vscode.window.createWebviewTextEditorInset(editor, line, height);
const newCtrlKId = this._idPool++
updateWebviewHTML(inset.webview, this._extensionUri, { jsOutLocation: 'dist/webviews/ctrlk/index.js', cssOutLocation: 'dist/webviews/styles.css' },
{ id: newCtrlKId }
)
ctrlKWebviewProvider.webview.then(webview => webview.postMessage({ type: 'ctrl+k', selection: { selectionStr, selectionRange, filePath } } satisfies MessageToSidebar));
}
// called by us
updateWebviewHTML(webview: vscode.Webview) {
_updateWebviewHTML(webview, this._extensionUri, { jsOutLocation: 'dist/webviews/ctrlk/index.js', cssOutLocation: 'dist/webviews/styles.css' })
onDisposeCtrlK() {
}
}

View file

@ -21,15 +21,10 @@ export class SidebarWebviewProvider implements vscode.WebviewViewProvider {
this._res = temp_res
}
// called by us
updateWebviewHTML(webview: vscode.Webview) {
_updateWebviewHTML(webview, this._extensionUri, { jsOutLocation: 'dist/webviews/sidebar/index.js', cssOutLocation: 'dist/webviews/styles.css' })
}
// called internally by vscode
resolveWebviewView(webviewView: vscode.WebviewView, context: vscode.WebviewViewResolveContext, token: vscode.CancellationToken,) {
const webview = webviewView.webview;
this.updateWebviewHTML(webview);
_updateWebviewHTML(webview, this._extensionUri, { jsOutLocation: 'dist/webviews/sidebar/index.js', cssOutLocation: 'dist/webviews/styles.css' })
this._res(webview); // resolve webview and _webviewView
}
}

View file

@ -0,0 +1,25 @@
import React, { ReactNode, createContext, useCallback, useContext, useEffect, useRef, useState, } from "react"
type PropsType = { [s: string]: any } | null
type PropsValue = { props: PropsType }
const PropsContext = createContext<PropsValue>(undefined as unknown as PropsValue)
// provider for whatever came in data-void-props
export function PropsProvider({ children, props }: { children: ReactNode, props: PropsType }) {
return (
<PropsContext.Provider value={{ props }}>
{children}
</PropsContext.Provider>
)
}
export function useVoidProps(): PropsValue {
const context = useContext<PropsValue>(PropsContext)
if (context === undefined) {
throw new Error("useVoidProps missing Provider")
}
return context
}

View file

@ -5,6 +5,7 @@ import { getVSCodeAPI, awaitVSCodeResponse, onMessageFromVSCode } from "./getVsc
import { initPosthog, identifyUser } from "./posthog";
import { ThreadsProvider } from "./contextForThreads";
import { ConfigProvider } from "./contextForConfig";
import { PropsProvider } from "./contextForProps";
const ListenersAndTracking = () => {
// initialize posthog
@ -47,14 +48,22 @@ export const mount = (children: React.ReactNode) => {
const rootElement = document.getElementById("root")!
console.log("Void root Element:", rootElement)
let props = rootElement.getAttribute("data-void-props")
let propsObj: object | null = null
if (props !== null) {
propsObj = JSON.parse(decodeURIComponent(props))
}
const content = (<>
<ListenersAndTracking />
<ThreadsProvider>
<ConfigProvider>
{children}
</ConfigProvider>
</ThreadsProvider>
<PropsProvider props={propsObj}>
<ThreadsProvider>
<ConfigProvider>
{children}
</ConfigProvider>
</ThreadsProvider>
</PropsProvider>
</>)
const root = ReactDOM.createRoot(rootElement)