mirror of
https://github.com/voideditor/void
synced 2026-05-23 09:28:23 +00:00
Merge branch 'main' into Gemini
This commit is contained in:
commit
cc3a08e1ab
16 changed files with 163 additions and 279 deletions
|
|
@ -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.
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
5
extensions/void/.vscode/launch.json
vendored
5
extensions/void/.vscode/launch.json
vendored
|
|
@ -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}"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
@ -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',
|
||||
|
|
|
|||
|
|
@ -10,6 +10,9 @@
|
|||
"categories": [
|
||||
"Other"
|
||||
],
|
||||
"enabledApiProposals": [
|
||||
"editorInsets"
|
||||
],
|
||||
"activationEvents": [],
|
||||
"main": "./out/extension/extension.js",
|
||||
"contributes": {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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<void>;
|
||||
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<DiffArea, 'diffareaid'> = {
|
||||
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
|
||||
// })
|
||||
// )
|
||||
|
||||
}
|
||||
|
|
@ -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<void> = new vscode.EventEmitter<void>(); // signals a UI refresh on .fire() events
|
||||
public readonly onDidChangeCodeLenses: vscode.Event<void> = 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
|
||||
|
|
|
|||
|
|
@ -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 }
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ export const updateWebviewHTML = (webview: vscode.Webview, extensionUri: vscode.
|
|||
<link href="${stylesUri}" rel="stylesheet">
|
||||
</head>
|
||||
<body>
|
||||
<div id="root" ${props ? `data-void-props="${encodeURIComponent(JSON.stringify(props))}"` : ''}></div>
|
||||
<div id="root"${props ? ` data-void-props="${encodeURIComponent(JSON.stringify(props))}"` : ''}></div>
|
||||
<script nonce="${nonce}" src="${scriptUri}"></script>
|
||||
</body>
|
||||
</html>`;
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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<PropsValue>(undefined as unknown as PropsValue)
|
||||
const PropsContext = createContext<any>(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<object | null>(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 (
|
||||
<PropsContext.Provider value={{ props }}>
|
||||
<PropsContext.Provider value={props}>
|
||||
{children}
|
||||
</PropsContext.Provider>
|
||||
)
|
||||
}
|
||||
|
||||
export function useVoidProps(): PropsValue {
|
||||
const context = useContext<PropsValue>(PropsContext)
|
||||
export function useVoidProps<T extends {}>(): T | null {
|
||||
// context is the "value" from above
|
||||
const context: T | null | undefined = useContext<T>(PropsContext)
|
||||
// only undefined if has no provider
|
||||
if (context === undefined) {
|
||||
throw new Error("useVoidProps missing Provider")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 = (<>
|
||||
<ListenersAndTracking />
|
||||
|
||||
<PropsProvider props={propsObj}>
|
||||
<PropsProvider rootElement={rootElement}>
|
||||
<ThreadsProvider>
|
||||
<ConfigProvider>
|
||||
{children}
|
||||
|
|
@ -69,4 +63,4 @@ export const mount = (children: React.ReactNode) => {
|
|||
const root = ReactDOM.createRoot(rootElement)
|
||||
root.render(content);
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
29
extensions/void/src/webviews/diffline/DiffLine.tsx
Normal file
29
extensions/void/src/webviews/diffline/DiffLine.tsx
Normal file
|
|
@ -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<props>()
|
||||
|
||||
console.log('props!', props)
|
||||
|
||||
if (!props) {
|
||||
return null
|
||||
}
|
||||
|
||||
// eslint-disable-next-line react/prop-types
|
||||
const text = props.text
|
||||
|
||||
return <>
|
||||
<div>
|
||||
{text}
|
||||
</div>
|
||||
</>
|
||||
};
|
||||
|
||||
7
extensions/void/src/webviews/diffline/index.tsx
Normal file
7
extensions/void/src/webviews/diffline/index.tsx
Normal file
|
|
@ -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(<DiffLine />)
|
||||
|
||||
Loading…
Reference in a new issue