commit 6d3677c72bc5e5c27761381a0050c4c993fe6bcc Author: Nathan Hedge <23344786+10Nates@users.noreply.github.com> Date: Wed Dec 20 03:36:55 2023 -0600 forgot to start a git history diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 0000000..f660e39 --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,20 @@ +/**@type {import('eslint').Linter.Config} */ +// eslint-disable-next-line no-undef +module.exports = { + root: true, + parser: '@typescript-eslint/parser', + plugins: [ + '@typescript-eslint', + ], + extends: [ + 'eslint:recommended', + 'plugin:@typescript-eslint/recommended', + ], + rules: { + 'semi': [2, "always"], + '@typescript-eslint/no-unused-vars': 0, + '@typescript-eslint/no-explicit-any': 0, + '@typescript-eslint/explicit-module-boundary-types': 0, + '@typescript-eslint/no-non-null-assertion': 0, + } +}; \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b2bf5b0 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +.DS_Store +/node_modules +/out +package-lock.json \ No newline at end of file diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000..af51550 --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,9 @@ +{ + // See https://go.microsoft.com/fwlink/?LinkId=827846 to learn about workspace recommendations. + // Extension identifier format: ${publisher}.${name}. Example: vscode.csharp + + // List of extensions which should be recommended for users of this workspace. + "recommendations": [ + "dbaeumer.vscode-eslint" + ] +} \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..e9e6097 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,22 @@ +// A launch configuration that compiles the extension and then opens it inside a new window +// Use IntelliSense to learn about possible attributes. +// Hover to view descriptions of existing attributes. +// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 +{ + "version": "0.2.0", + "configurations": [ + { + "name": "Run Extension", + "type": "extensionHost", + "request": "launch", + "runtimeExecutable": "${execPath}", + "args": [ + "--extensionDevelopmentPath=${workspaceFolder}" + ], + "outFiles": [ + "${workspaceFolder}/out/**/*.js" + ], + "preLaunchTask": "npm: watch" + } + ] +} diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..e46111f --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "editor.insertSpaces": false +} \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000..241aa6d --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,20 @@ +// See https://go.microsoft.com/fwlink/?LinkId=733558 +// for the documentation about the tasks.json format +{ + "version": "2.0.0", + "tasks": [ + { + "type": "npm", + "script": "watch", + "problemMatcher": "$tsc-watch", + "isBackground": true, + "presentation": { + "reveal": "never" + }, + "group": { + "kind": "build", + "isDefault": true + } + } + ] +} \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..26926b7 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023 Nathan B. (10Nates) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..2422c77 --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +# Ollama Coder + +An ollama-based autocompletion engine. diff --git a/package.json b/package.json new file mode 100644 index 0000000..a60dfb4 --- /dev/null +++ b/package.json @@ -0,0 +1,60 @@ +{ + "name": "ollama-coder", + "displayName": "Ollama Coder", + "version": "0.0.1", + "publisher": "10nates", + "license": "MIT", + "repository": { + "type": "git", + "url": "https://github.com/10Nates/ollama-coder" + }, + "engines": { + "vscode": "^1.73.0" + }, + "categories": [ + "Other" + ], + "activationEvents": [ + "*" + ], + "main": "./out/extension.js", + "contributes": { + "configuration": { + "title": "Ollama Coder", + "properties": { + "ollama-coder.endpoint": { + "type": "string", + "default": "http://localhost:11434/api/generate", + "description": "The endpoint of the ollama REST API" + }, + "ollama-coder.model": { + "type": "string", + "default": "deepseek-coder", + "description": "The model to use for generating completions" + }, + "ollama-coder.system-message": { + "type": "string | undefined", + "default": null, + "description": "The system message to use for code completions" + } + } + } + }, + "scripts": { + "vscode:prepublish": "npm run compile", + "compile": "tsc -p ./", + "lint": "eslint \"src/**/*.ts\"", + "watch": "tsc -watch -p ./" + }, + "devDependencies": { + "@types/node": "^16.18.34", + "@types/vscode": "^1.73.0", + "@typescript-eslint/eslint-plugin": "^6.7.0", + "@typescript-eslint/parser": "^6.7.0", + "eslint": "^8.26.0", + "typescript": "^5.3.2" + }, + "dependencies": { + "axios": "^1.6.2" + } +} diff --git a/src/extension.ts b/src/extension.ts new file mode 100644 index 0000000..8f69485 --- /dev/null +++ b/src/extension.ts @@ -0,0 +1,151 @@ +// Significant help from GPT4 + +import * as vscode from "vscode"; +import axios from "axios"; + +const apiEndpoint: string = vscode.workspace.getConfiguration("ollama-coder").get("apiEndpoint") || "http://localhost:11434/api/generate"; +const apiModel: string = vscode.workspace.getConfiguration("ollama-coder").get("model") || "deepseek-coder"; +const apiSystemMessage: string | undefined = vscode.workspace.getConfiguration("ollama-coder").get("system-message"); +const documentRange = 2000; + +// This method is called when your extension is activated +function activate(context: vscode.ExtensionContext) { + console.log("Ollama Coder is Active"); + // Register a completion provider for JavaScript files + const provider = vscode.languages.registerCompletionItemProvider("javascript", { + async provideCompletionItems(document, position) { + // Get the current prompt + const prompt = document.lineAt(position.line).text.substring(0, position.character); + // Check if the prompt is not empty and ends with a dot + if (prompt) { + // Create a completion item + const item = new vscode.CompletionItem("Autocomplete with Ollama"); + // Set the insert text to a placeholder + item.insertText = new vscode.SnippetString('${1:}'); + // Set the documentation to a message + item.documentation = new vscode.MarkdownString('Press `Enter` to get a completion from Ollama'); + // Set the command to trigger the completion + item.command = { + command: 'ollama-coder.autocomplete', + title: 'Ollama', + arguments: [document, position, prompt] + }; + // Return the completion item + return [item]; + } + }, + }, + "." + ); + + // Add the completion provider to the context + context.subscriptions.push(provider); + + // Register a command for getting a completion from Ollama + const disposable = vscode.commands.registerCommand( + "ollama-coder.autocomplete", + async function (document, position, prompt) { + // Show a progress message + vscode.window.withProgress( + { + location: vscode.ProgressLocation.Notification, + title: "Getting a completion from Ollama...", + }, + async (progress, token) => { + try { + // Make a request to the ollama.ai REST API + const response = await axios.post(apiEndpoint, { + model: apiModel, // Change this to the model you want to use + prompt: prompt, + stream: false, + system: apiSystemMessage, + options: { + num_predict: 100 + } + } + ); + // Get the completion from the response + const completion = response.data.response; + // Check if the completion is not empty + if (completion) { + // Insert the completion into the document + const edit = new vscode.WorkspaceEdit(); + const range = new vscode.Range( + position.line, + position.character, + position.line, + position.character + ); + edit.replace(document.uri, range, completion); + await vscode.workspace.applyEdit(edit); + // Move the cursor to the end of the completion + const newPosition = position.with( + position.line, + position.character + completion.length + ); + const newSelection = new vscode.Selection( + newPosition, + newPosition + ); + const editor = vscode.window.activeTextEditor; + if (editor) editor.selection = newSelection; + } else { + // Show a warning message + vscode.window.showWarningMessage("Ollama could not generate a completion for this prompt"); + console.log("Ollama could not generate a completion for this prompt"); + } + } catch (err: any) { + // Show an error message + vscode.window.showErrorMessage( + "Ollama encountered an error: " + err.message + ); + console.log("Ollama encountered an error: " + err.message); + } + } + ); + } + ); + + // Add the command to the context + context.subscriptions.push(disposable); +} + +// get a a completion from Ollama +async function autocomplete(document: vscode.TextDocument, position: vscode.Position, prompt: string) { + try { + // Make a request to the ollama.ai REST API + const response = await axios.post(apiEndpoint, { + model: apiModel, // Change this to the model you want to use + prompt: prompt, + stream: false, + system: apiSystemMessage, + options: { + num_predict: 10 + } + }); + // Get the completion from the response + const completion = response.data.response; + // Check if the completion is not empty + if (completion) { + return completion; + } else { + // Show a warning message + vscode.window.showWarningMessage("Ollama could not generate a completion for this prompt"); + console.log("Ollama could not generate a completion for this prompt"); + } + } catch (err: any) { + // Show an error message + vscode.window.showErrorMessage( + "Ollama encountered an error: " + err.message + ); + console.log("Ollama encountered an error: " + err.message); + } +} + +// This method is called when your extension is deactivated +function deactivate() { } + +module.exports = { + activate, + deactivate, +}; diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..bbe3dc3 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "module": "commonjs", + "target": "es2020", + "lib": ["es2020"], + "outDir": "out", + "sourceMap": true, + "strict": true, + "rootDir": "src" + }, + "exclude": [ + "node_modules", + ".vscode-test" + ] +}