Skip to content

Commit 6169745

Browse files
committed
use workspace.showInputPalette instead of NotificationRequest
Signed-off-by: Tobias Wolf <[email protected]>
1 parent 23d7979 commit 6169745

File tree

3 files changed

+98
-44
lines changed

3 files changed

+98
-44
lines changed

README.md

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
1-
This Nova extension integrates [ollama](https://ollama.com) to help you *complete code* or *generate code* based on a prompt.
1+
This Nova extension integrates [ollama](https://ollama.com) to help you *complete code* or *generate code* based on a prompt. This extension was developed to use code completion without external services, to ensure privacy and to be independent of online services.
22

33
The extension comes with two commands, `Assist` and `Complete code`.
44

5+
<video src="https://github.com/tobiasfabian/nova-ollama/assets/1524319/6b3058e8-a9d1-4d1e-b511-e4943aac11c8" autoplay muted loop width="600"></video>
6+
7+
<video src="https://github.com/tobiasfabian/nova-ollama/assets/1524319/2de55322-989a-4e13-bf4e-660688d5ab09" autoplay muted loop width="600"></video>
8+
59

610
## Requirements
711

@@ -21,6 +25,7 @@ To run one of these commands
2125
- Select the **Editor → ollama** menu item and click on `Assist` or `Complete code`
2226
- Open **Command Palette …** (`shift + cmd + p`) and type `Assist` or `Complete code`
2327

28+
The `Assist` command is bind to `cmd + opt + ctrl + p`. To change the key binding, open the **Settings**, got to **Key Bindings** and search for *Assist*.
2429

2530
### Configuration
2631

@@ -58,20 +63,18 @@ Controls how long the model will stay loaded into memory following the request
5863
#### System message “Complete code”
5964
Default:
6065
```
61-
You are a code autocompletion engine. Respond with a continuation of the code provided and nothing else. Don’t format code. Don’t put code in code block. Don’t repeat the input.
66+
You are a code autocompletion engine. Respond with a continuation of the code provided and nothing else. Code should not be in a code block. Anything that is not code should be written as a code comment.
6267
```
6368

64-
This system message is used when you run the “Complete code” command. You can try different messages to fine tune the output.
69+
This system message is used when you run the “Complete code” command. You can try different messages to fine-tune the output.
6570

6671
#### System message “Assist”
6772
Default:
6873
```
69-
You are an assistant helping with coding. Respond with code only. Don’t format code. Don’t put code in code block. Don’t repeat the input.
74+
You are an assistant helping with coding. Respond with code only. Don’t format code. Don’t put code in code blocks. Don’t repeat the input.
7075
```
7176

72-
This system message is used when you run the “Assist” command. You can try different messages to fine tune the output.
77+
This system message is used when you run the “Assist” command. You can try different messages to fine-tune the output.
7378

7479
### Privacy
7580
This extension needs **Send Network Requests** permission to send and receive requests to the locally running ollama server. No data will be sent to external servers.
76-
77-
> This Nova extension is briefly inspired by [ollama-autocoder (VS Code extension)](https://github.com/10Nates/ollama-autocoder)

Scripts/main.js

Lines changed: 77 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,12 @@
44

55
const encoder = new TextDecoder();
66

7+
// Toggle which controls insertStream()
8+
let continueReading = true;
9+
710
let ollamaOrigin = nova.config.get('tobiaswolf.ollama.origin') ?? 'http://localhost:11434';
811
let apiUrl = `${ollamaOrigin}/api`;
9-
let modelName = nova.config.get('tobiaswolf.ollama.modelName') ?? llama2;
12+
let modelName = nova.config.get('tobiaswolf.ollama.modelName') ?? 'llama2';
1013

1114
const checkIfModelExists = async () => {
1215
try {
@@ -39,6 +42,8 @@ const showError = async (message) => {
3942

4043
const requestOllama = async (input, apiSystem) => {
4144
try {
45+
openCancelNotificationRequest();
46+
4247
if (input === '') {
4348
console.log(`No input provided. ${input}`);
4449
return;
@@ -84,13 +89,28 @@ const cleanResponseText = (responseText, editor) => {
8489
return responseText;
8590
}
8691

92+
const interruptCodeGeneration = () => {
93+
// set continueReading toggle
94+
continueReading = false;
95+
setTimeout(() => {
96+
continueReading = true;
97+
}, 500);
98+
}
99+
87100
const insertStream = async (reader, editor) => {
88101
return await new Promise((resolve, reject) => {
89102
let responseText = '';
90103
const startInputPosition = editor.selectedRange.end;
91104
let inputPosition = startInputPosition;
92105

93106
const readStream = () => {
107+
if (continueReading === false) {
108+
const inputRange = new Range(startInputPosition, startInputPosition + responseText.length);
109+
110+
editor.addSelectionForRange(inputRange);
111+
return reject('Stream reading interrupted');
112+
}
113+
94114
reader.read().then(async ({ done, value }) => {
95115
const data = JSON.parse(encoder.decode(value));
96116
let responseTextChunk = data.response;
@@ -121,6 +141,7 @@ const insertStream = async (reader, editor) => {
121141
newInputRange = new Range(startInputPosition, startInputPosition + responseText.length);
122142

123143
editor.addSelectionForRange(newInputRange);
144+
nova.notifications.cancel('ollama-cancel-request');
124145
resolve(responseText);
125146
} else {
126147
readStream();
@@ -136,45 +157,74 @@ const insertStream = async (reader, editor) => {
136157
});
137158
}
138159

160+
161+
162+
const openCancelNotificationRequest = async () => {
163+
const notificationRequest = new NotificationRequest("ollama-cancel-request");
164+
notificationRequest.title = nova.localize("Cancel output?");
165+
notificationRequest.actions = [nova.localize("Cancel output")];
166+
167+
const promise = nova.notifications.add(notificationRequest);
168+
promise.then(async (reply) => {
169+
if (reply.actionIdx === 0) {
170+
console.info('Cancel output');
171+
interruptCodeGeneration();
172+
}
173+
});
174+
}
175+
139176
const completeCode = async (editor) => {
140-
var selectedRanges = editor.selectedRanges.reverse();
141-
for (var range of selectedRanges) {
142-
// get selected text
143-
let input = editor.getTextInRange(range);
144-
if (input === '') {
177+
try {
178+
var selectedRange = editor.selectedRange;
179+
const selectedText = editor.selectedText;
180+
let input = selectedText;
181+
if (selectedText === '') {
145182
// get text from cursor to beginning of file
146-
input = editor.getTextInRange(new Range(0, range.end));
183+
input = editor.getTextInRange(new Range(0, selectedRange.end));
147184
}
148185
const systemMessageCompleteCode = nova.config.get('tobiaswolf.ollama.systemMessageCompleteCode');
149186
const response = await requestOllama(input, systemMessageCompleteCode);
150187
const responseText = await insertStream(response.body.getReader(), editor);
188+
} catch (exception) {
189+
console.error(exception);
151190
}
152191
}
153192

154193
const openAssistant = async (editor) => {
155-
let notificationRequest = new NotificationRequest("ollama-assistant");
156-
const syntax = editor.document.syntax;
157-
158-
notificationRequest.title = nova.localize("How can I assist you?");
159-
notificationRequest.body = nova.localize(`Language: ${syntax}`);
160-
161-
if (syntax) {
162-
notificationRequest.textInputValue = `${syntax}: `;
163-
}
194+
try {
195+
const syntax = editor.document.syntax;
164196

165-
notificationRequest.type = "input";
166-
notificationRequest.actions = [nova.localize("OK"), nova.localize("Cancel")];
197+
const selectedText = editor.selectedText;
198+
let inputMessage = 'Write a command.';
167199

168-
let promise = nova.notifications.add(notificationRequest);
169-
promise.then(async (reply) => {
170-
if (reply.actionIdx === 0) {
171-
const systemMessageAssist = nova.config.get('tobiaswolf.ollama.systemMessageAssist');
172-
const response = await requestOllama(reply.textInputValue, systemMessageAssist)
173-
const responseText = await insertStream(response.body.getReader(), editor);
200+
if (selectedText !== '') {
201+
inputMessage = 'Write a command, selected text is added to the end of the command.';
174202
}
175-
}, error => {
176-
console.error(error);
177-
});
203+
204+
nova.workspace.showInputPalette(inputMessage, {
205+
value: syntax ? `${syntax}: ` : null,
206+
placeholder: 'JS: Fetch request with json reponse.',
207+
}, async (input) => {
208+
console.log(input);
209+
if (input) {
210+
if (selectedText !== '') {
211+
input += `
212+
213+
${selectedText}
214+
`
215+
}
216+
try {
217+
const systemMessageAssist = nova.config.get('tobiaswolf.ollama.systemMessageAssist');
218+
const response = await requestOllama(input, systemMessageAssist)
219+
const responseText = await insertStream(response.body.getReader(), editor);
220+
} catch (exception) {
221+
console.error(exception);
222+
}
223+
}
224+
});
225+
} catch (exception) {
226+
console.error(exception);
227+
}
178228
};
179229

180230

@@ -183,7 +233,6 @@ const openAssistant = async (editor) => {
183233
nova.config.onDidChange('tobiaswolf.ollama.origin', (disposable) => {
184234
ollamaOrigin = disposable;
185235
apiUrl = `${ollamaOrigin}/api`;
186-
console.log(apiUrl);
187236
checkIfModelExists();
188237
});
189238
nova.config.onDidChange('tobiaswolf.ollama.modelName', (disposable) => {

extension.json

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
"license": "MIT",
88
"repository": "https://github.com/tobiasfabian/nova-ollama",
99
"bugs": "https://github.com/tobiasfabian/nova-ollama/issues",
10+
"funding": "https://github.com/sponsors/tobiasfabian",
1011
"categories": [
1112
"commands"
1213
],
@@ -22,7 +23,8 @@
2223
},
2324
{
2425
"title": "Assist",
25-
"command": "tobiaswolf.ollama.assist"
26+
"command": "tobiaswolf.ollama.assist",
27+
"shortcut": "cmd-opt-ctrl-p"
2628
}
2729
]
2830
},
@@ -61,16 +63,16 @@
6163
"key": "tobiaswolf.ollama.systemMessageCompleteCode",
6264
"title": "System message “Complete code”",
6365
"type": "text",
64-
"placeholder": "e.g. “You are a code autocompletion engine. Respond with a continuation of the code provided and nothing else. Don’t format code. Don’t put code in code block. Don’t repeat the input.”",
65-
"default": "You are a code autocompletion engine. Respond with a continuation of the code provided and nothing else. Don’t format code. Don’t put code in code block. Don’t repeat the input.",
66+
"placeholder": "e.g. “You are a code autocompletion engine. Respond with a continuation of the code provided and nothing else. Code should not be in a code block. Anything that is not code should be written as a code comment.”",
67+
"default": "You are a code autocompletion engine. Respond with a continuation of the code provided and nothing else. Code should not be in a code block. Anything that is not code should be written as a code comment.",
6668
"description": "This system message is used, when you run the “Complete code” command."
6769
},
6870
{
6971
"key": "tobiaswolf.ollama.systemMessageAssist",
7072
"title": "System message “Assist”",
7173
"type": "text",
72-
"placeholder": "e.g. “You are an assistant helping with coding. Respond with code only. Don’t format code. Don’t put code in code block. Don’t repeat the input.”",
73-
"default": "You are an assistant helping with coding. Respond with code only. Don’t format code. Don’t put code in code block. Don’t repeat the input.",
74+
"placeholder": "e.g. “You are an assistant helping with coding. Respond with code only. Don’t format code. Don’t put code in code blocks. Don’t repeat the input.”",
75+
"default": "You are an assistant helping with coding. Respond with code only. Don’t format code. Don’t put code in code blocks. Don’t repeat the input.",
7476
"description": "This system message is used, when you run the “Assist” command."
7577
}
7678
],
@@ -109,16 +111,16 @@
109111
"key": "tobiaswolf.ollama.systemMessageCompleteCode",
110112
"title": "System message “Complete code”",
111113
"type": "text",
112-
"placeholder": "e.g. “You are a code autocompletion engine. Respond with a continuation of the code provided and nothing else. Don’t format code. Don’t put code in code block. Don’t repeat the input.”",
113-
"default": "You are a code autocompletion engine. Respond with a continuation of the code provided and nothing else. Don’t format code. Don’t put code in code block. Don’t repeat the input.",
114+
"placeholder": "e.g. “You are a code autocompletion engine. Respond with a continuation of the code provided and nothing else. Code should not be in a code block. Anything that is not code should be written as a code comment.”",
115+
"default": "You are a code autocompletion engine. Respond with a continuation of the code provided and nothing else. Code should not be in a code block. Anything that is not code should be written as a code comment.",
114116
"description": "This system message is used, when you run the “Complete code” command."
115117
},
116118
{
117119
"key": "tobiaswolf.ollama.systemMessageAssist",
118120
"title": "System message “Assist”",
119121
"type": "text",
120-
"placeholder": "e.g. “You are an assistant helping with coding. Respond with code only. Don’t format code. Don’t put code in code block. Don’t repeat the input.”",
121-
"default": "You are an assistant helping with coding. Respond with code only. Don’t format code. Don’t put code in code block. Don’t repeat the input.",
122+
"placeholder": "e.g. “You are an assistant helping with coding. Respond with code only. Don’t format code. Don’t put code in code blocks. Don’t repeat the input.”",
123+
"default": "You are an assistant helping with coding. Respond with code only. Don’t format code. Don’t put code in code blocks. Don’t repeat the input.",
122124
"description": "This system message is used, when you run the “Assist” command."
123125
}
124126
]

0 commit comments

Comments
 (0)