diff --git a/.devcontainer/README.md b/.devcontainer/README.md index 5f6e1cd9..dd59adb6 100644 --- a/.devcontainer/README.md +++ b/.devcontainer/README.md @@ -56,7 +56,7 @@ Next: **[Try it out!](#try-it)** You may see improved VNC responsiveness when accessing a codespace from VS Code client since you can use a [VNC Viewer][def]. Here's how to do it. -1. Install [Visual Studio Code Stable](https://code.visualstudio.com/) or [Insiders](https://code.visualstudio.com/insiders/) and the the [GitHub Codespaces extension](https://marketplace.visualstudio.com/items?itemName=GitHub.codespaces). +1. Install [Visual Studio Code Stable](https://code.visualstudio.com/) or [Insiders](https://code.visualstudio.com/insiders/) and the [GitHub Codespaces extension](https://marketplace.visualstudio.com/items?itemName=GitHub.codespaces). > **Note:** The GitHub Codespaces extension requires the Visual Studio Code distribution of Code - OSS. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index afc17efb..0125ac46 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -51,17 +51,18 @@ If you're using a Mac, make sure you have Python and XCode installed (you probab If you're using a Windows computer, first get [Visual Studio 2022](https://visualstudio.microsoft.com/thank-you-downloading-visual-studio/?sku=Community) (recommended) or [VS Build Tools](https://visualstudio.microsoft.com/thank-you-downloading-visual-studio/?sku=BuildTools) (not recommended). If you already have both, you might need to run the next few steps on both of them. -Find the box for Visual Studio 2022 (or VS Build Tools) and click Install/Modify. +Open the installer for Visual Studio 2022 (or VS Build Tools). This is often automatic. -Under Workloads, select "Desktop development with C++" and "Node.js build tools". - -Under Individual components, select every item under: +Go to the "Workloads" tab and select: +- `Desktop development with C++` +- `Node.js build tools` +Go to the "Individual Components" tab and select: - `MSVC v143 - VS 2022 C++ x64/x86 Spectre-mitigated libs (Latest)`, - `C++ ATL for latest build tools with Spectre Mitigations`, - `C++ MFC for latest build tools with Spectre Mitigations`. -Finally, click Install/Modify. +Finally, click Install. ### c. Build Prerequisites - Linux @@ -69,7 +70,7 @@ We haven't created prerequisite steps for building on Linux yet, but you can fol ### Build instructions -Before building Void, please follow the prerequisite steps above for your operating system. Also make sure you've already built the Void extension (or just run `cd ./extensions/void && npm install && npm run build && npm run compile && cd ../..`). +Before building Void, please follow the prerequisite steps above for your operating system. Also, make sure you've already built and compiled the Void extension (or just run `cd ./extensions/void && npm install && npm run build && npm run compile && cd ../..`). To build Void, first open `void/` in VSCode. Then: @@ -146,7 +147,9 @@ We're always glad to talk about new ideas, help you get set up, and make sure yo ## Submitting a Pull Request -Please submit a pull request once you've made a change. You don't need to submit an issue. +Please submit a pull request once you've made a change. You don't need to submit an issue. + +Please don't use AI to write your PR 🙂. # Relevant files diff --git a/extensions/void/.vscode/launch.json b/extensions/void/.vscode/launch.json index 88804653..17ab1d57 100644 --- a/extensions/void/.vscode/launch.json +++ b/extensions/void/.vscode/launch.json @@ -10,7 +10,8 @@ "type": "extensionHost", "request": "launch", "args": [ - "--extensionDevelopmentPath=${workspaceFolder}" + "--extensionDevelopmentPath=${workspaceFolder}", + "--enable-proposed-api=void.void", ], "outFiles": [ "${workspaceFolder}/out/**/*.js" @@ -18,4 +19,4 @@ "preLaunchTask": "${defaultBuildTask}" } ] -} +} \ No newline at end of file diff --git a/extensions/void/build/build.js b/extensions/void/build/build.js index 8b2ab8be..d1be3bb0 100644 --- a/extensions/void/build/build.js +++ b/extensions/void/build/build.js @@ -49,6 +49,11 @@ const convertTSXtoJS = async ({ from, to }) => { to: 'dist/webviews/ctrlk/index.js', }) + await convertTSXtoJS({ + from: 'src/webviews/diffline/index.tsx', + to: 'dist/webviews/diffline/index.js', + }) + // convert tailwind to css await convertTailwindToCSS({ from: 'src/webviews/styles.css', diff --git a/extensions/void/package.json b/extensions/void/package.json index bcfc55af..50748687 100644 --- a/extensions/void/package.json +++ b/extensions/void/package.json @@ -10,6 +10,9 @@ "categories": [ "Other" ], + "enabledApiProposals": [ + "editorInsets" + ], "activationEvents": [], "main": "./out/extension/extension.js", "contributes": { diff --git a/extensions/void/src/common/sendLLMMessage.ts b/extensions/void/src/common/sendLLMMessage.ts index 361e8011..c6c5b6a0 100644 --- a/extensions/void/src/common/sendLLMMessage.ts +++ b/extensions/void/src/common/sendLLMMessage.ts @@ -238,25 +238,38 @@ export const sendOllamaMsg: SendLLMMessageFnTypeInternal = ({ messages, onText, let didAbort = false let fullText = "" - // if abort is called, onFinalMessage is NOT called, and no later onTexts are called either abortRef.current = () => { didAbort = true; }; const ollama = new Ollama({ host: voidConfig.ollama.endpoint }) - ollama.chat({ - model: voidConfig.ollama.model, - messages: messages, - stream: true, - options: { num_predict: parseMaxTokensStr(voidConfig.default.maxTokens) } // this is max_tokens - }) + // First check if model exists + ollama.list() + .then(async models => { + const installedModels = models.models.map(m => m.name.replace(/:latest$/, '')) + const modelExists = installedModels.some(m => m.startsWith(voidConfig.ollama.model)); + if (!modelExists) { + const errorMessage = `The model "${voidConfig.ollama.model}" is not available locally. Please run 'ollama pull ${voidConfig.ollama.model}' to download it first or + try selecting one from the Installed models: ${installedModels.join(', ')}`; + onText(errorMessage, errorMessage); + onFinalMessage(errorMessage); + return Promise.reject(); + } + + return ollama.chat({ + model: voidConfig.ollama.model, + messages: messages, + stream: true, + options: { num_predict: parseMaxTokensStr(voidConfig.default.maxTokens) } + }); + }) .then(async stream => { + if (!stream) return; + abortRef.current = () => { - // stream.abort() didAbort = true } - // iterate through the stream for await (const chunk of stream) { if (didAbort) return; const newText = chunk.message.content; @@ -264,13 +277,17 @@ export const sendOllamaMsg: SendLLMMessageFnTypeInternal = ({ messages, onText, onText(newText, fullText); } onFinalMessage(fullText); - }) - // when error/fail .catch(error => { - onError(error) - }) - + // Check if the error is a connection error + if (error instanceof Error && error.message.includes('Failed to fetch')) { + const errorMessage = 'Ollama service is not running. Please start the Ollama service and try again.'; + onText(errorMessage, errorMessage); + onFinalMessage(errorMessage); + } else if (error) { + onError(error); + } + }); }; // Greptile diff --git a/extensions/void/src/extension.ts b/extensions/void/src/extension.ts deleted file mode 100644 index 581b03b0..00000000 --- a/extensions/void/src/extension.ts +++ /dev/null @@ -1,196 +0,0 @@ -import * as vscode from 'vscode'; - -import { DiffArea, ChatThreads, MessageFromSidebar, MessageToSidebar } from './common/shared_types'; -import { v4 as uuidv4 } from 'uuid' -import { AbortRef } from './common/sendLLMMessage'; -import { DiffProvider } from './extension/DiffProvider'; -import { SidebarWebviewProvider } from './extension/providers/SidebarWebviewProvider'; -import { getVoidConfigFromPartial } from './webviews/common/contextForConfig'; -import { applyDiffLazily } from './extension/ctrlL'; -import { readFileContentOfUri } from './extension/extensionLib/readFileContentOfUri'; - -// 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; - dispose(): void; - } - export namespace window { - export function createWebviewTextEditorInset(editor: vscode.TextEditor, line: number, height: number, options?: vscode.WebviewOptions): WebviewEditorInset; - } -} - -const roundRangeToLines = (selection: vscode.Selection) => { - let endLine = selection.end.character === 0 ? selection.end.line - 1 : selection.end.line // e.g. if the user triple clicks, it selects column=0, line=line -> column=0, line=line+1 - return new vscode.Range(selection.start.line, 0, endLine, Number.MAX_SAFE_INTEGER) -} - -const getSelection = (editor: vscode.TextEditor) => { - // get the range of the selection and the file the user is in - const selectionRange = roundRangeToLines(editor.selection); - const selectionStr = editor.document.getText(selectionRange).trim(); - const filePath = editor.document.uri; - return { selectionStr, filePath } -} - -export function activate(context: vscode.ExtensionContext) { - - // 1. Mount the chat sidebar - const sidebarWebviewProvider = new SidebarWebviewProvider(context); - context.subscriptions.push( - vscode.window.registerWebviewViewProvider(SidebarWebviewProvider.viewId, sidebarWebviewProvider, { webviewOptions: { retainContextWhenHidden: true } }) - ); - - - - // 2. ctrl+l - context.subscriptions.push( - vscode.commands.registerCommand('void.ctrl+l', () => { - const editor = vscode.window.activeTextEditor - if (!editor) return - - // show the sidebar - vscode.commands.executeCommand('workbench.view.extension.voidViewContainer'); - // vscode.commands.executeCommand('vscode.moveViewToPanel', CustomViewProvider.viewId); // move to aux bar - - const { selectionStr, filePath } = getSelection(editor) - - // send message to the webview (Sidebar.tsx) - sidebarWebviewProvider.webview.then(webview => webview.postMessage({ type: 'ctrl+l', selection: { selectionStr, filePath } } satisfies MessageToSidebar)); - }) - ); - - // 2.5: ctrl+k - context.subscriptions.push( - vscode.commands.registerCommand('void.ctrl+k', () => { - console.log('CTRLK PRESSED') - const editor = vscode.window.activeTextEditor - if (!editor) return - - const { selectionStr, filePath } = getSelection(editor) - - // send message to the webview (Sidebar.tsx) - sidebarWebviewProvider.webview.then(webview => webview.postMessage({ type: 'ctrl+k', selection: { selectionStr, filePath } } satisfies MessageToSidebar)); - }) - ); - - // 3. Show an approve/reject codelens above each change - const diffProvider = new DiffProvider(); - context.subscriptions.push(vscode.languages.registerCodeLensProvider('*', diffProvider)); - - // 4. Add approve/reject commands - context.subscriptions.push(vscode.commands.registerCommand('void.acceptDiff', async (params) => { - diffProvider.acceptDiff(params) - })); - context.subscriptions.push(vscode.commands.registerCommand('void.rejectDiff', async (params) => { - diffProvider.rejectDiff(params) - })); - - // 5. Receive messages from sidebar - sidebarWebviewProvider.webview.then( - webview => { - - // top navigation bar commands - context.subscriptions.push(vscode.commands.registerCommand('void.startNewThread', async () => { - webview.postMessage({ type: 'startNewThread' } satisfies MessageToSidebar) - })) - context.subscriptions.push(vscode.commands.registerCommand('void.toggleThreadSelector', async () => { - webview.postMessage({ type: 'toggleThreadSelector' } satisfies MessageToSidebar) - })) - context.subscriptions.push(vscode.commands.registerCommand('void.toggleSettings', async () => { - webview.postMessage({ type: 'toggleSettings' } satisfies MessageToSidebar) - })); - - // Receive messages in the extension from the sidebar webview (messages are sent using `postMessage`) - webview.onDidReceiveMessage(async (m: MessageFromSidebar) => { - - const abortApplyRef: AbortRef = { current: null } - - if (m.type === 'requestFiles') { - - // get contents of all file paths - const files = await Promise.all( - m.filepaths.map(async (filepath) => ({ filepath, content: await readFileContentOfUri(filepath) })) - ) - - // send contents to webview - webview.postMessage({ type: 'files', files, } satisfies MessageToSidebar) - - } - else if (m.type === 'applyChanges') { - - const editor = vscode.window.activeTextEditor - if (!editor) { - vscode.window.showInformationMessage('No active editor!') - return - } - // create an area to show diffs - const partialDiffArea: Omit = { - startLine: 0, // in ctrl+L the start and end lines are the full document - endLine: editor.document.lineCount, - originalStartLine: 0, - originalEndLine: editor.document.lineCount, - sweepIndex: null, - } - const diffArea = diffProvider.createDiffArea(editor.document.uri, partialDiffArea, await readFileContentOfUri(editor.document.uri)) - - const docUri = editor.document.uri - const fileStr = await readFileContentOfUri(docUri) - const voidConfig = getVoidConfigFromPartial(context.globalState.get('partialVoidConfig') ?? {}) - - await applyDiffLazily({ docUri, oldFileStr: fileStr, diffRepr: m.diffRepr, voidConfig, diffProvider, diffArea, abortRef: abortApplyRef }) - } - else if (m.type === 'getPartialVoidConfig') { - const partialVoidConfig = context.globalState.get('partialVoidConfig') ?? {} - webview.postMessage({ type: 'partialVoidConfig', partialVoidConfig } satisfies MessageToSidebar) - } - else if (m.type === 'persistPartialVoidConfig') { - const partialVoidConfig = m.partialVoidConfig - context.globalState.update('partialVoidConfig', partialVoidConfig) - } - else if (m.type === 'getAllThreads') { - const threads: ChatThreads = context.workspaceState.get('allThreads') ?? {} - webview.postMessage({ type: 'allThreads', threads } satisfies MessageToSidebar) - } - else if (m.type === 'persistThread') { - const threads: ChatThreads = context.workspaceState.get('allThreads') ?? {} - const updatedThreads: ChatThreads = { ...threads, [m.thread.id]: m.thread } - context.workspaceState.update('allThreads', updatedThreads) - } - else if (m.type === 'getDeviceId') { - let deviceId = context.globalState.get('void_deviceid') - if (!deviceId || typeof deviceId !== 'string') { - deviceId = uuidv4() - context.globalState.update('void_deviceid', deviceId) - } - webview.postMessage({ type: 'deviceId', deviceId: deviceId as string } satisfies MessageToSidebar) - } - else { - console.error('unrecognized command', m) - } - }) - } - ) - - - - - // Gets called when user presses ctrl + k (mounts ctrl+k-style codelens) - // TODO need to build this - // const ctrlKCodeLensProvider = new CtrlKCodeLensProvider(); - // context.subscriptions.push(vscode.languages.registerCodeLensProvider('*', ctrlKCodeLensProvider)); - // context.subscriptions.push( - // vscode.commands.registerCommand('void.ctrl+k', () => { - // const editor = vscode.window.activeTextEditor; - // if (!editor) - // return - // ctrlKCodeLensProvider.addNewCodeLens(editor.document, editor.selection); - // // vscode.commands.executeCommand('editor.action.showHover'); // apparently this refreshes the codelenses by having the internals call provideCodeLenses - // }) - // ) - -} diff --git a/extensions/void/src/extension/DiffProvider.ts b/extensions/void/src/extension/DiffProvider.ts index ca567b4c..9836dfde 100644 --- a/extensions/void/src/extension/DiffProvider.ts +++ b/extensions/void/src/extension/DiffProvider.ts @@ -3,6 +3,7 @@ import { findDiffs } from './findDiffs'; import { throttle } from 'lodash'; import { DiffArea, BaseDiff, Diff } from '../common/shared_types'; import { readFileContentOfUri } from './extensionLib/readFileContentOfUri'; +import { updateWebviewHTML } from './extensionLib/updateWebviewHTML'; const THROTTLE_TIME = 100 @@ -31,6 +32,8 @@ export class DiffProvider implements vscode.CodeLensProvider { private _diffareaidPool = 0 private _diffidPool = 0 + private _extensionUri: vscode.Uri + // used internally by vscode private _onDidChangeCodeLenses: vscode.EventEmitter = new vscode.EventEmitter(); // signals a UI refresh on .fire() events public readonly onDidChangeCodeLenses: vscode.Event = this._onDidChangeCodeLenses.event; @@ -42,7 +45,8 @@ export class DiffProvider implements vscode.CodeLensProvider { } // declared by us, registered with vscode.languages.registerCodeLensProvider() - constructor() { + constructor(context: vscode.ExtensionContext) { + this._extensionUri = context.extensionUri console.log('Creating DisplayChangesProvider') @@ -210,6 +214,21 @@ export class DiffProvider implements vscode.CodeLensProvider { ) ); + // update red highlighting + // this._diffsOfDocument[docUriStr] + // .filter(diff => diff.originalCode !== '') + // .forEach(diff => { + // const text = originalFile.split('\n').slice(diff.originalRange.start.line, diff.originalRange.start.line + 1).join('\n') + // const height = text.split('\n').length + // const line = diff.range.start.line - 1 + + // const inset = vscode.window.createWebviewTextEditorInset(editor, line, height); + // updateWebviewHTML(inset.webview, this._extensionUri, { jsOutLocation: 'dist/webviews/diffline/index.js', cssOutLocation: 'dist/webviews/styles.css' }, + // { text } + // ) + + + // }) // for each diffArea, highlight its sweepIndex in dark gray editor.setDecorations( @@ -234,8 +253,6 @@ export class DiffProvider implements vscode.CodeLensProvider { ) ) - // TODO update red highlighting - // this._diffsOfDocument[docUriStr].map(diff => diff.deletedCode) // update code lenses this._onDidChangeCodeLenses.fire() @@ -392,7 +409,7 @@ export class DiffProvider implements vscode.CodeLensProvider { // figure out where to highlight based on where the AI is in the stream right now, use the last diff in findDiffs to figure that out const diffs = findDiffs(originalDiffAreaCode, newDiffAreaCode) - const lastDiff = diffs[diffs.length - 1] ?? null + const lastDiff = diffs?.[diffs.length - 1] ?? null // these are two different coordinate systems - new and old line number let newFileEndLine: number // get new[0...newStoppingPoint] with line=newStoppingPoint highlighted diff --git a/extensions/void/src/extension/ctrlL.ts b/extensions/void/src/extension/applyDiffLazily.ts similarity index 94% rename from extensions/void/src/extension/ctrlL.ts rename to extensions/void/src/extension/applyDiffLazily.ts index 2837638f..9b350082 100644 --- a/extensions/void/src/extension/ctrlL.ts +++ b/extensions/void/src/extension/applyDiffLazily.ts @@ -134,7 +134,7 @@ Return \`true\` if ANY part of the chunk should be modified, and \`false\` if it // lazily applies the diff to the file // we chunk the text in the file, and ask an LLM whether it should edit each chunk -const applyDiffLazily = async ({ docUri, oldFileStr, voidConfig, abortRef, diffRepr, diffProvider, diffArea }: { docUri: vscode.Uri, oldFileStr: string, diffRepr: string, voidConfig: VoidConfig, diffProvider: DiffProvider, diffArea: DiffArea, abortRef: AbortRef }) => { +export const applyDiffLazily = async ({ docUri, oldFileStr, voidConfig, abortRef, diffRepr, diffProvider, diffArea }: { docUri: vscode.Uri, oldFileStr: string, diffRepr: string, voidConfig: VoidConfig, diffProvider: DiffProvider, diffArea: DiffArea, abortRef: AbortRef }) => { // stateful variables @@ -179,7 +179,3 @@ const applyDiffLazily = async ({ docUri, oldFileStr, voidConfig, abortRef, diffR } - - - -export { applyDiffLazily } diff --git a/extensions/void/src/extension/extension.ts b/extensions/void/src/extension/extension.ts index 9cba5293..cc7cbed6 100644 --- a/extensions/void/src/extension/extension.ts +++ b/extensions/void/src/extension/extension.ts @@ -1,13 +1,14 @@ import * as vscode from 'vscode'; -import { applyDiffLazily } from './ctrlL'; -import { readFileContentOfUri } from './extensionLib/readFileContentOfUri'; -import { MessageToSidebar, MessageFromSidebar, DiffArea, ChatThreads } from '../common/shared_types'; -import { DiffProvider } from './DiffProvider'; -import { getVoidConfigFromPartial } from '../webviews/common/contextForConfig'; -import { CtrlKWebviewProvider } from './providers/CtrlKWebviewProvider'; -import { SidebarWebviewProvider } from './providers/SidebarWebviewProvider'; + import { v4 as uuidv4 } from 'uuid' import { AbortRef } from '../common/sendLLMMessage'; +import { MessageToSidebar, MessageFromSidebar, DiffArea, ChatThreads } from '../common/shared_types'; +import { getVoidConfigFromPartial } from '../webviews/common/contextForConfig'; +import { applyDiffLazily } from './applyDiffLazily'; +import { DiffProvider } from './DiffProvider'; +import { readFileContentOfUri } from './extensionLib/readFileContentOfUri'; +import { SidebarWebviewProvider } from './providers/SidebarWebviewProvider'; +import { CtrlKWebviewProvider } from './providers/CtrlKWebviewProvider'; // this comes from vscode.proposed.editorInsets.d.ts declare module 'vscode' { @@ -25,7 +26,16 @@ declare module 'vscode' { } const roundRangeToLines = (selection: vscode.Selection) => { - return new vscode.Range(selection.start.line, 0, selection.end.line, Number.MAX_SAFE_INTEGER) + let endLine = selection.end.character === 0 ? selection.end.line - 1 : selection.end.line // e.g. if the user triple clicks, it selects column=0, line=line -> column=0, line=line+1 + return new vscode.Range(selection.start.line, 0, endLine, Number.MAX_SAFE_INTEGER) +} + +const getSelection = (editor: vscode.TextEditor) => { + // get the range of the selection and the file the user is in + const selectionRange = roundRangeToLines(editor.selection); + const selectionStr = editor.document.getText(selectionRange).trim(); + const filePath = editor.document.uri; + return { selectionStr, filePath } } export function activate(context: vscode.ExtensionContext) { @@ -50,14 +60,7 @@ export function activate(context: vscode.ExtensionContext) { vscode.commands.executeCommand('workbench.view.extension.voidViewContainer'); // vscode.commands.executeCommand('vscode.moveViewToPanel', CustomViewProvider.viewId); // move to aux bar - // get the range of the selection - const selectionRange = roundRangeToLines(editor.selection); - - // get the text the user is selecting - const selectionStr = editor.document.getText(selectionRange); - - // get the file the user is in - const filePath = editor.document.uri; + const { selectionStr, filePath } = getSelection(editor) // send message to the webview (Sidebar.tsx) sidebarWebviewProvider.webview.then(webview => webview.postMessage({ type: 'ctrl+l', selection: { selectionStr, filePath } } satisfies MessageToSidebar)); @@ -71,22 +74,16 @@ export function activate(context: vscode.ExtensionContext) { const editor = vscode.window.activeTextEditor if (!editor) return - // get the range of the selection - const selectionRange = roundRangeToLines(editor.selection); - - // get the text the user is selecting - const selectionStr = editor.document.getText(selectionRange); - - // get the file the user is in - const filePath = editor.document.uri; + const { selectionStr, filePath } = getSelection(editor) // send message to the webview (Sidebar.tsx) - ctrlKWebviewProvider.onPressCtrlK() + // ctrlKWebviewProvider.onPressCtrlK() + // sidebarWebviewProvider.webview.then(webview => webview.postMessage({ type: 'ctrl+k', selection: { selectionStr, filePath } } satisfies MessageToSidebar)); }) ); // 3. Show an approve/reject codelens above each change - const diffProvider = new DiffProvider(); + const diffProvider = new DiffProvider(context); context.subscriptions.push(vscode.languages.registerCodeLensProvider('*', diffProvider)); // 4. Add approve/reject commands diff --git a/extensions/void/src/extension/extensionLib/updateWebviewHTML.ts b/extensions/void/src/extension/extensionLib/updateWebviewHTML.ts index 1957ac75..d237d4be 100644 --- a/extensions/void/src/extension/extensionLib/updateWebviewHTML.ts +++ b/extensions/void/src/extension/extensionLib/updateWebviewHTML.ts @@ -32,7 +32,7 @@ export const updateWebviewHTML = (webview: vscode.Webview, extensionUri: vscode. -
+
`; diff --git a/extensions/void/src/webviews/common/contextForConfig.tsx b/extensions/void/src/webviews/common/contextForConfig.tsx index d62e692c..7cfc11a0 100644 --- a/extensions/void/src/webviews/common/contextForConfig.tsx +++ b/extensions/void/src/webviews/common/contextForConfig.tsx @@ -120,11 +120,11 @@ const voidConfigInfo: Record< 'http://127.0.0.1:11434' ), // TODO we should allow user to select model inside Void, but for now we'll just let them handle the Ollama setup on their own - // model: configEnum( - // 'Ollama model to use.', - // 'llama3.1', - // ["codegemma", "codegemma:2b", "codegemma:7b", "codellama", "codellama:7b", "codellama:13b", "codellama:34b", "codellama:70b", "codellama:code", "codellama:python", "command-r", "command-r:35b", "command-r-plus", "command-r-plus:104b", "deepseek-coder-v2", "deepseek-coder-v2:16b", "deepseek-coder-v2:236b", "falcon2", "falcon2:11b", "firefunction-v2", "firefunction-v2:70b", "gemma", "gemma:2b", "gemma:7b", "gemma2", "gemma2:2b", "gemma2:9b", "gemma2:27b", "llama2", "llama2:7b", "llama2:13b", "llama2:70b", "llama3", "llama3:8b", "llama3:70b", "llama3-chatqa", "llama3-chatqa:8b", "llama3-chatqa:70b", "llama3-gradient", "llama3-gradient:8b", "llama3-gradient:70b", "llama3.1", "llama3.1:8b", "llama3.1:70b", "llama3.1:405b", "llava", "llava:7b", "llava:13b", "llava:34b", "llava-llama3", "llava-llama3:8b", "llava-phi3", "llava-phi3:3.8b", "mistral", "mistral:7b", "mistral-large", "mistral-large:123b", "mistral-nemo", "mistral-nemo:12b", "mixtral", "mixtral:8x7b", "mixtral:8x22b", "moondream", "moondream:1.8b", "openhermes", "openhermes:v2.5", "phi3", "phi3:3.8b", "phi3:14b", "phi3.5", "phi3.5:3.8b", "qwen", "qwen:7b", "qwen:14b", "qwen:32b", "qwen:72b", "qwen:110b", "qwen2", "qwen2:0.5b", "qwen2:1.5b", "qwen2:7b", "qwen2:72b", "smollm", "smollm:135m", "smollm:360m", "smollm:1.7b"] as const - // ), + model: configEnum( + 'Ollama model to use.', + 'llama3.1', + ["codegemma", "codegemma:2b", "codegemma:7b", "codellama", "codellama:7b", "codellama:13b", "codellama:34b", "codellama:70b", "codellama:code", "codellama:python", "command-r", "command-r:35b", "command-r-plus", "command-r-plus:104b", "deepseek-coder-v2", "deepseek-coder-v2:16b", "deepseek-coder-v2:236b", "falcon2", "falcon2:11b", "firefunction-v2", "firefunction-v2:70b", "gemma", "gemma:2b", "gemma:7b", "gemma2", "gemma2:2b", "gemma2:9b", "gemma2:27b", "llama2", "llama2:7b", "llama2:13b", "llama2:70b", "llama3", "llama3:8b", "llama3:70b", "llama3-chatqa", "llama3-chatqa:8b", "llama3-chatqa:70b", "llama3-gradient", "llama3-gradient:8b", "llama3-gradient:70b", "llama3.1", "llama3.2", "llama3.1:8b", "llama3.1:70b", "llama3.1:405b", "llava", "llava:7b", "llava:13b", "llava:34b", "llava-llama3", "llava-llama3:8b", "llava-phi3", "llava-phi3:3.8b", "mistral", "mistral:7b", "mistral-large", "mistral-large:123b", "mistral-nemo", "mistral-nemo:12b", "mixtral", "mixtral:8x7b", "mixtral:8x22b", "moondream", "moondream:1.8b", "openhermes", "openhermes:v2.5", "phi3", "phi3:3.8b", "phi3:14b", "phi3.5", "phi3.5:3.8b", "qwen", "qwen:7b", "qwen:14b", "qwen:32b", "qwen:72b", "qwen:110b", "qwen2", "qwen2:0.5b", "qwen2:1.5b", "qwen2:7b", "qwen2:72b", "smollm", "smollm:135m", "smollm:360m", "smollm:1.7b"] as const + ), }, openRouter: { model: configString( diff --git a/extensions/void/src/webviews/common/contextForProps.tsx b/extensions/void/src/webviews/common/contextForProps.tsx index 25f73abf..6775fcb1 100644 --- a/extensions/void/src/webviews/common/contextForProps.tsx +++ b/extensions/void/src/webviews/common/contextForProps.tsx @@ -1,22 +1,33 @@ import React, { ReactNode, createContext, useCallback, useContext, useEffect, useRef, useState, } from "react" -type PropsType = { [s: string]: any } | null - -type PropsValue = { props: PropsType } - -const PropsContext = createContext(undefined as unknown as PropsValue) +const PropsContext = createContext(undefined as unknown as any) // provider for whatever came in data-void-props -export function PropsProvider({ children, props }: { children: ReactNode, props: PropsType }) { +export function PropsProvider({ children, rootElement }: { children: ReactNode, rootElement: HTMLElement }) { + + const [props, setProps] = useState(null) + + // update props when rootElement changes + useEffect(() => { + let props = rootElement.getAttribute("data-void-props") + let propsObj: object | null = null + if (props !== null) { + propsObj = JSON.parse(decodeURIComponent(props)) + } + setProps(propsObj) + }, [rootElement]) + return ( - + {children} ) } -export function useVoidProps(): PropsValue { - const context = useContext(PropsContext) +export function useVoidProps(): T | null { + // context is the "value" from above + const context: T | null | undefined = useContext(PropsContext) + // only undefined if has no provider if (context === undefined) { throw new Error("useVoidProps missing Provider") } diff --git a/extensions/void/src/webviews/common/mount.tsx b/extensions/void/src/webviews/common/mount.tsx index 70ef66f6..a07b46b7 100644 --- a/extensions/void/src/webviews/common/mount.tsx +++ b/extensions/void/src/webviews/common/mount.tsx @@ -46,18 +46,12 @@ export const mount = (children: React.ReactNode) => { // mount the sidebar on the id="root" element 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)) - } + // console.log("Void root Element:", rootElement) const content = (<> - + {children} @@ -69,4 +63,4 @@ export const mount = (children: React.ReactNode) => { const root = ReactDOM.createRoot(rootElement) root.render(content); -} \ No newline at end of file +} diff --git a/extensions/void/src/webviews/diffline/DiffLine.tsx b/extensions/void/src/webviews/diffline/DiffLine.tsx new file mode 100644 index 00000000..6fbe8b6c --- /dev/null +++ b/extensions/void/src/webviews/diffline/DiffLine.tsx @@ -0,0 +1,29 @@ +import React, { useState } from 'react'; +import { useOnVSCodeMessage } from '../common/getVscodeApi'; +import { useVoidProps } from '../common/contextForProps'; + + +type props = { + text: string +} + +export const DiffLine = () => { + + const props = useVoidProps() + + console.log('props!', props) + + if (!props) { + return null + } + + // eslint-disable-next-line react/prop-types + const text = props.text + + return <> +
+ {text} +
+ +}; + diff --git a/extensions/void/src/webviews/diffline/index.tsx b/extensions/void/src/webviews/diffline/index.tsx new file mode 100644 index 00000000..dc9a59b9 --- /dev/null +++ b/extensions/void/src/webviews/diffline/index.tsx @@ -0,0 +1,7 @@ +import React from "react" +import { mount } from "../common/mount" +import { DiffLine } from "./DiffLine" + +// this is the entry point that mounts diffline +mount() +