Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DEV2-4340 - inline chat interaction added #1406

Closed
wants to merge 8 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -481,6 +481,10 @@
{
"key": "ctrl+shift+q",
"command": "tabnine.chat.focus-input"
},
{
"key": "ctrl+i",
"command": "tabnine.chat.commands.inline.action"
}
]
},
Expand Down
66 changes: 66 additions & 0 deletions src/tabnineChatWidget/extensionCommands/ChatActionProvider.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/* eslint-disable class-methods-use-this */
import {
CodeAction,
CodeActionContext,
CodeActionKind,
ExtensionContext,
Range,
TextDocument,
languages,
CodeActionProvider,
} from "vscode";
import { languagesFilter } from "./const";

export function registerChatActionProvider(context: ExtensionContext) {
context.subscriptions.push(
languages.registerCodeActionsProvider(
languagesFilter,
new ChatActionProvider(),
{
providedCodeActionKinds: [
CodeActionKind.RefactorRewrite,
CodeActionKind.QuickFix,
],
}
)
);
}

class ChatActionProvider implements CodeActionProvider {
provideCodeActions(
document: TextDocument,
range: Range,
codeActionContext: CodeActionContext & {
triggerKind: number;
}
): CodeAction[] {
if (codeActionContext.triggerKind !== 1) {
return [];
}
const resultActions: CodeAction[] = [];

if (codeActionContext.diagnostics[0]?.range) {
const fixAction = new CodeAction(
"Fix with Tabnine",
CodeActionKind.QuickFix
);

fixAction.command = {
title: fixAction.title,
command: "tabnine.chat.commands.fix-code",
};
resultActions.push(fixAction);
}
const refactor = new CodeAction(
"Ask Tabnine",
CodeActionKind.RefactorRewrite
);

refactor.command = {
title: refactor.title,
command: "tabnine.chat.commands.inline.action",
};
resultActions.push(refactor);
return resultActions;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,40 +3,37 @@ import {
CancellationToken,
CodeLens,
CodeLensProvider,
commands,
Diagnostic,
DiagnosticSeverity,
DocumentSymbol,
Event,
EventEmitter,
ExtensionContext,
languages,
Location,
SymbolInformation,
SymbolKind,
TextDocument,
Uri,
} from "vscode";
import { fireEvent } from "../../../binary/requests/requests";

export type Intents = "test" | "fix" | "explain" | "document";
export type Actions =
| "generate-test-for-code"
| "fix-code"
| "explain-code"
| "document-code";

const CODE_LENS_ACTIONS: [Intents, Actions][] = [
["test", "generate-test-for-code"],
["fix", "fix-code"],
["explain", "explain-code"],
["document", "document-code"],
];

const VALID_SYMBOLS = [SymbolKind.Function, SymbolKind.Method];
import { fireEvent } from "../../binary/requests/requests";
import { getFuctionsSymbols } from "./getFuctionsSymbols";
import { Action, CODE_LENS_COMMANDS } from "./commands";
import tabnineExtensionProperties from "../../globals/tabnineExtensionProperties";
import { languagesFilter } from "./const";

const MAX_LINES = 2500;

export class ChatCodeLensProvider implements CodeLensProvider {
export default function registerChatCodeLens(context: ExtensionContext) {
if (!tabnineExtensionProperties.codeLensEnabled) {
return;
}
context.subscriptions.push(
languages.registerCodeLensProvider(
languagesFilter,
new ChatCodeLensProvider()
)
);
}

class ChatCodeLensProvider implements CodeLensProvider {
private visitedFiles: Set<Uri> = new Set();

private didChangeCodeLenses = new EventEmitter<void>();
Expand All @@ -54,9 +51,8 @@ export class ChatCodeLensProvider implements CodeLensProvider {
return [];
}

const documnetSymbols = await commands.executeCommand<
(SymbolInformation & DocumentSymbol)[]
>("vscode.executeDocumentSymbolProvider", document.uri);
const documnetSymbols = await getFuctionsSymbols(document);

if (!documnetSymbols?.length) {
return [];
}
Expand All @@ -72,25 +68,9 @@ export class ChatCodeLensProvider implements CodeLensProvider {

const lenses: CodeLens[] = [];

documnetSymbols
?.filter((fn) => VALID_SYMBOLS.includes(fn.kind))
.forEach(({ location }) =>
lenses.push(...toIntentLens(location, diagnostic), toAskLens(location))
);

documnetSymbols
?.filter((symbol) => symbol.kind === SymbolKind.Class)
.forEach((classSymbol) =>
classSymbol.children
.filter((child) => VALID_SYMBOLS.includes(child.kind))
.forEach((method) => {
const { location } = (method as unknown) as SymbolInformation;
lenses.push(
...toIntentLens(location, diagnostic),
toAskLens(location)
);
})
);
documnetSymbols.forEach(({ location }) => {
lenses.push(...toIntentLens(location, diagnostic), toAskLens(location));
});

if (!this.visitedFiles.has(document.uri)) {
this.visitedFiles.add(document.uri);
Expand Down Expand Up @@ -128,20 +108,22 @@ function toIntentLens(
location: Location,
diagnostics: Diagnostic[]
): CodeLens[] {
return CODE_LENS_ACTIONS.filter(([text]) =>
return CODE_LENS_COMMANDS.filter(({ text }) =>
filterRelevantActions(text, location, diagnostics)
).map(
([text, action], index) =>
new CodeLens(location.range, {
title: `${index === 0 ? "tabnine: " : ""}${text}`,
tooltip: `tabnine ${text}`,
command: "tabnine.chat.commands.any",
arguments: [location.range, action],
})
);
)
.sort((a, b) => a.lensOrder - b.lensOrder)
.map(
({ text, intent }, index) =>
new CodeLens(location.range, {
title: `${index === 0 ? "tabnine: " : ""}${text}`,
tooltip: `tabnine ${text}`,
command: "tabnine.chat.commands.any",
arguments: [location.range, intent],
})
);
}
function filterRelevantActions(
text: Intents,
text: Action,
location: Location,
diagnostics: Diagnostic[]
): boolean {
Expand Down
85 changes: 0 additions & 85 deletions src/tabnineChatWidget/extensionCommands/codeLens/index.ts

This file was deleted.

77 changes: 77 additions & 0 deletions src/tabnineChatWidget/extensionCommands/commands.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
export type Scope = "block" | "selection" | "none";
export type Action = "test" | "fix" | "explain" | "document" | "workspace";
export type Intent =
| "/generate-test-for-code"
| "/fix-code"
| "/explain-code"
| "/document-code"
| "/workspace";

enum LensOrder {
test = 1,
fix = 2,
explain = 3,
document = 4,
}

export type Command = {
label: string;
text: Action;
intent: Intent;
description: string;
scope: Scope[];
multistep: boolean;
};
export type LensCommand = Command & { lensOrder: number };

export const CODE_LENS_COMMANDS: LensCommand[] = [
{
label: "$(feedback) explain",
text: "explain",
intent: "/explain-code",
description: "Explain the selected code",
scope: ["selection", "block"],
multistep: false,
lensOrder: LensOrder.explain,
},
{
label: "$(beaker) test",
text: "test",
intent: "/generate-test-for-code",
description: "Write tests for the selected code",
scope: ["block"],
multistep: false,
lensOrder: LensOrder.test,
},
{
label: "$(checklist) document",
text: "document",
intent: "/document-code",
description: "Add documentation for the selected code",
scope: ["block"],
multistep: false,
lensOrder: LensOrder.document,
},
{
label: "$(symbol-property) fix",
text: "fix",
intent: "/fix-code",
description: "Find errors in the selected code and fix them",
scope: ["block"],
multistep: false,
lensOrder: LensOrder.fix,
},
];

export const COMANDS: Command[] = [
...CODE_LENS_COMMANDS,
{
label: "$(search) workspace",
text: "workspace",
intent: "/workspace",
description:
"Ask a question related to any code within your current workspace",
scope: ["none"],
multistep: true,
},
];
16 changes: 16 additions & 0 deletions src/tabnineChatWidget/extensionCommands/const.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
export const languagesFilter = [
{ language: "javascript" },
{ pattern: "**/*[!d].ts", scheme: "file" },
{ language: "javascriptreact" },
{ language: "typescriptreact" },
{ language: "python" },
{ language: "ruby" },
{ language: "go" },
{ language: "rust" },
{ language: "swift" },
{ language: "java" },
{ language: "c" },
{ language: "cpp" },
{ language: "csharp" },
{ language: "php" },
];
Loading
Loading