Skip to content

Commit

Permalink
[VSCode Extension] UI enhancements (#786)
Browse files Browse the repository at this point in the history
* Features added

1. Generate code with user selected text only
2. Add right-click menus, "Generate Inline Code Completion" and Generate Inline Code Completion In New Tab"

* Update modules/openvino_code/README.md
  • Loading branch information
luke-lin-vmc authored Jan 29, 2024
1 parent d2f1b23 commit 2726609
Show file tree
Hide file tree
Showing 7 changed files with 137 additions and 29 deletions.
2 changes: 2 additions & 0 deletions modules/openvino_code/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ To check the connection manually, use the `Check Connection` button located on t
1. Create a new Python file or open an existing one.
1. Type `def main():` or place the cursor where you'd like code suggestions to be generated.
1. Press the keyboard shortcut `Ctrl+Alt+Space` (`Cmd+Alt+Space` for macOS) or click the `Generate Code Completion` button located in the side panel.
1. You can select the text then generate the related code.
1. You may also right-click on "Generate Inline Code Completion In New Tab" to generate code in a new tab.
1. Use the `Tab` key to accept the entire suggestion or `Ctrl`+`Right Arrow` to accept it word by word. To decline the suggestion, press `Esc`.

You can customize the length of the generated code by adjusting `Max New Tokens` and `Min New Tokens` parameters in the extension settings.
Expand Down
28 changes: 28 additions & 0 deletions modules/openvino_code/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,11 @@
"category": "OpenVINO Code",
"title": "Generate Inline Code Completion"
},
{
"command": "openvinoCode.generateInlineCompletionTab",
"category": "OpenVINO Code",
"title": "Generate Inline Code Completion In New Tab"
},
{
"command": "openvinoCode.generateDocstring",
"category": "OpenVINO Code",
Expand Down Expand Up @@ -159,6 +164,23 @@
"when": "view == openvino-code-side-panel",
"group": "navigation"
}
],
"editor/context": [
{
"command": "openvino-code-completion.toggle",
"group": "openvino-code-completion",
"when": "editorTextFocus && config.openvino-code-completion.showCommandsInContextMenu"
},
{
"command": "openvinoCode.generateInlineCompletion",
"when": "editorFocus",
"group": "openvino-code-completion@1"
},
{
"command": "openvinoCode.generateInlineCompletionTab",
"when": "editorFocus",
"group": "openvino-code-completion@2"
}
]
},
"configuration": [
Expand Down Expand Up @@ -264,6 +286,12 @@
"mac": "ctrl+alt+space",
"when": "editorTextFocus"
},
{
"command": "openvinoCode.generateInlineCompletionTab",
"key": "ctrl+alt+shift+1",
"mac": "ctrl+alt+shift+1",
"when": "editorTextFocus"
},
{
"command": "openvinoCode.stopGeneration",
"key": "escape",
Expand Down
1 change: 1 addition & 0 deletions modules/openvino_code/src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export const COMMANDS = {
FOCUS_SIDE_PANEL: `${SIDE_PANEL_VIEW_ID}.focus`,
OPEN_SETTINGS: 'openvinoCode.openSettings',
GENERATE_INLINE_COPMLETION: 'openvinoCode.generateInlineCompletion',
GENERATE_INLINE_COPMLETION_TAB: 'openvinoCode.generateInlineCompletionTab',
ACCEPT_INLINE_COMPLETION: 'openvinoCode.acceptInlineCompletion',
GENERATE_DOC_STRING: 'openvinoCode.generateDocstring',
CHECK_CONNECTION: 'openvinoCode.checkConnection',
Expand Down
43 changes: 43 additions & 0 deletions modules/openvino_code/src/inline-completion/completion.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import { InlineCompletionItem, Position, Range, TextDocument, window } from 'vsc
import { EXTENSION_DISPLAY_NAME } from '../constants';
import { IGenerateRequest, backendService } from '../services/backend.service';
import { extensionState } from '../state';
import * as vscode from 'vscode';
import { getIsGeneralTabActive } from './tab';

const outputChannel = window.createOutputChannel(EXTENSION_DISPLAY_NAME, { log: true });
const logCompletionInput = (input: string): void => outputChannel.append(`Completion input:\n${input}\n\n`);
Expand Down Expand Up @@ -31,6 +33,47 @@ class CompletionService {
if (fillInTheMiddleMode && textAfterCursor.trim()) {
return `${startToken}${textBeforeCursor}${middleToken}${textAfterCursor}${endToken}`;
}

const editor = window.activeTextEditor;
if (!editor) {
return ``; // No open text editor
}

if (getIsGeneralTabActive() === true){
const text = editor.document.getText();
const currentPosition = editor.selection.active;
const selectedText = editor.document.getText(editor.selection);
//const logContent = `Cursor Position: Line ${currentPosition.line + 1}, Character ${currentPosition.character + 1}\nSelected Text: ${selectedText}`;

vscode.workspace.openTextDocument({ content: text }).then(doc => {
vscode.window.showTextDocument(doc, { viewColumn: vscode.ViewColumn.Beside }).then(TabTextEditor => {
const newPosition = new vscode.Position((currentPosition.line + 1), (currentPosition.character + 1));
const newSelection = new vscode.Selection(newPosition, newPosition);
TabTextEditor.selection = newSelection;
},
error => {
// Failed to open the document
console.error('Error:', error);
}
);
},
error => {
// Failed to open the document
console.error('Error:', error);
}
);

if (selectedText !== ``){
return selectedText;
} else {
return textBeforeCursor;
}
}

if (!editor.selection.isEmpty) {
const selectedText = editor.document.getText(editor.selection)
return selectedText;
}
return textBeforeCursor;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { IExtensionComponent } from '../extension-component.interface';
import { notificationService } from '../services/notification.service';
import { extensionState } from '../state';
import { CommandInlineCompletionItemProvider } from './command-inline-completion-provider';
import { setIsGeneralTabActive } from './tab';

class InlineCompletion implements IExtensionComponent {
private _disposables: Disposable[] = [];
Expand All @@ -14,39 +15,50 @@ class InlineCompletion implements IExtensionComponent {

let commandInlineCompletionDisposable: Disposable;

const generateCommandDisposable = commands.registerCommand(COMMANDS.GENERATE_INLINE_COPMLETION, () => {
if (!extensionState.get('isServerAvailable')) {
notificationService.showServerNotAvailableMessage(extensionState.state);
return;
}
if (extensionState.get('isLoading') && window.activeTextEditor) {
void window.showTextDocument(window.activeTextEditor.document);
return;
}

extensionState.set('isLoading', true);

if (commandInlineCompletionDisposable) {
commandInlineCompletionDisposable.dispose();
}

commandInlineCompletionDisposable = languages.registerInlineCompletionItemProvider(
{ pattern: '**' },
commandInlineCompletionProvider
);

void commandInlineCompletionProvider.triggerCompletion(() => {
commandInlineCompletionDisposable.dispose();
extensionState.set('isLoading', false);
});
});
function generateFunction(): void {
if (!extensionState.get('isServerAvailable')) {
notificationService.showServerNotAvailableMessage(extensionState.state);
return;
}
if (extensionState.get('isLoading') && window.activeTextEditor) {
void window.showTextDocument(window.activeTextEditor.document);
return;
}
extensionState.set('isLoading', true);
if (commandInlineCompletionDisposable) {
commandInlineCompletionDisposable.dispose();
}
commandInlineCompletionDisposable = languages.registerInlineCompletionItemProvider(
{ pattern: '**' },
commandInlineCompletionProvider
);
void commandInlineCompletionProvider.triggerCompletion(() => {
commandInlineCompletionDisposable.dispose();
extensionState.set('isLoading', false);
});
}

const acceptCommandDisposable = commands.registerCommand(COMMANDS.ACCEPT_INLINE_COMPLETION, () => {
void commands.executeCommand('editor.action.inlineSuggest.commit');
});

const generateCommandDisposable = commands.registerCommand(COMMANDS.GENERATE_INLINE_COPMLETION, () => {
setIsGeneralTabActive(false);
generateFunction();
});
context.subscriptions.push(generateCommandDisposable, acceptCommandDisposable);
this._disposables.push(generateCommandDisposable, acceptCommandDisposable);

const generateTabCommandDisposable = commands.registerCommand(COMMANDS.GENERATE_INLINE_COPMLETION_TAB, () => {
setIsGeneralTabActive(true);
generateFunction();
});
context.subscriptions.push(generateTabCommandDisposable, acceptCommandDisposable);
this._disposables.push(generateTabCommandDisposable, acceptCommandDisposable);
}

deactivate(): void {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { IExtensionComponent } from '../extension-component.interface';
import { extensionState } from '../state';
import { StreamingCommandInlineCompletionItemProvider } from './streaming-command-inline-completion-provider';
import { notificationService } from '../services/notification.service';
import { setIsGeneralTabActive } from './tab';

class StreamingInlineCompletion implements IExtensionComponent {
private _disposables: Disposable[] = [];
Expand All @@ -29,7 +30,7 @@ class StreamingInlineCompletion implements IExtensionComponent {
generationDisposables = [];
}

const generateCommandDisposable = commands.registerCommand(COMMANDS.GENERATE_INLINE_COPMLETION, () => {
function generateFunction(): void {
if (!extensionState.get('isServerAvailable')) {
notificationService.showServerNotAvailableMessage(extensionState.state);
return;
Expand Down Expand Up @@ -69,14 +70,26 @@ class StreamingInlineCompletion implements IExtensionComponent {
// TODO: handle unsetting context on error thrown from triggerCompletion
void commands.executeCommand('setContext', EXTENSION_CONTEXT_STATE.GENERATING, false);
});
});
}

const acceptCommandDisposable = commands.registerCommand(COMMANDS.ACCEPT_INLINE_COMPLETION, () => {
void commands.executeCommand('editor.action.inlineSuggest.commit');
});


const generateCommandDisposable = commands.registerCommand(COMMANDS.GENERATE_INLINE_COPMLETION, () => {
// Update the boolean variable
setIsGeneralTabActive(false);
generateFunction();
});
context.subscriptions.push(generateCommandDisposable, acceptCommandDisposable);
this._disposables.push(generateCommandDisposable, acceptCommandDisposable);

const generateTabCommandDisposable = commands.registerCommand(COMMANDS.GENERATE_INLINE_COPMLETION_TAB, () => {
setIsGeneralTabActive(true);
generateFunction();
});
context.subscriptions.push(generateTabCommandDisposable, acceptCommandDisposable);
this._disposables.push(generateTabCommandDisposable, acceptCommandDisposable);
}

deactivate(): void {
Expand Down
9 changes: 9 additions & 0 deletions modules/openvino_code/src/inline-completion/tab.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
let isGeneralTabActiveInternal: boolean = false;

export function setIsGeneralTabActive(value: boolean): void {
isGeneralTabActiveInternal = value;
}

export function getIsGeneralTabActive(): boolean {
return isGeneralTabActiveInternal;
}

0 comments on commit 2726609

Please sign in to comment.