-
Notifications
You must be signed in to change notification settings - Fork 193
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* detect when a document is opened for diff * fix how we decide a diff editor is open, and show some dummy comment * make addComments async + prettier * support returning multiple threads when commenting * invoke real api to get comments * use diff to query for changes only on changed file * support removing a code review comment * lint + prettier * Add status bar message when fetching suggestions * prettier * downgrade axios to fix build * fix tabnine icon in comments * cleanup * display formatted code in suggestions * lint + prettier * support applying a suggestion * cleanup * fire events * not needed * do not sent code snippets * do not do anythong if CODE_REVIEW capability is not enabled * lint + prettier * pr comments * remove unneeded * lint + prettier
- Loading branch information
1 parent
1505f93
commit 0f39ccf
Showing
14 changed files
with
467 additions
and
3 deletions.
There are no files selected for viewing
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
import { CommentThread, Uri } from "vscode"; | ||
|
||
export default class DocumentThreads { | ||
readonly uri: Uri; | ||
|
||
private readonly threads: CommentThread[]; | ||
|
||
constructor(uri: Uri, threads: CommentThread[]) { | ||
this.uri = uri; | ||
this.threads = threads; | ||
} | ||
|
||
dispose(): void { | ||
this.threads.forEach((thread) => thread.dispose()); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
import { | ||
CommentMode, | ||
CommentThread, | ||
Uri, | ||
MarkdownString, | ||
Comment, | ||
CommentAuthorInformation, | ||
workspace, | ||
WorkspaceEdit, | ||
TextDocument, | ||
} from "vscode"; | ||
import { fireEvent } from "../binary/requests/requests"; | ||
import * as api from "./api"; | ||
|
||
export default class TabnineComment implements Comment { | ||
suggestion: api.Suggestion; | ||
|
||
language: string; | ||
|
||
oldValue: string; | ||
|
||
constructor(oldValue: string, suggestion: api.Suggestion, language: string) { | ||
this.oldValue = oldValue; | ||
this.suggestion = suggestion; | ||
this.language = language; | ||
} | ||
|
||
get body(): MarkdownString { | ||
return new MarkdownString().appendCodeblock( | ||
this.suggestion.value, | ||
this.language | ||
); | ||
} | ||
|
||
// eslint-disable-next-line class-methods-use-this | ||
get mode(): CommentMode { | ||
return CommentMode.Preview; | ||
} | ||
|
||
// eslint-disable-next-line class-methods-use-this | ||
get author(): CommentAuthorInformation { | ||
const iconUri = Uri.parse( | ||
"https://www.tabnine.com/favicons/favicon-32x32.png" | ||
); | ||
return { name: "Tabnine", iconPath: iconUri }; | ||
} | ||
|
||
apply(thread: CommentThread): boolean { | ||
const document = documentOf(thread); | ||
|
||
if (!document) { | ||
this.fireEvent("comment-applied", thread, { | ||
success: false, | ||
failureReason: "doument not found", | ||
}); | ||
return false; | ||
} | ||
|
||
const oldText = document.getText(thread.range); | ||
|
||
if (this.oldValue !== oldText.trim()) { | ||
this.fireEvent("comment-applied", thread, { | ||
success: false, | ||
failureReason: "text did not match", | ||
}); | ||
return false; | ||
} | ||
|
||
const edit = new WorkspaceEdit(); | ||
edit.replace(thread.uri, thread.range, this.suggestion.value); | ||
void workspace.applyEdit(edit); | ||
|
||
this.fireEvent("comment-applied", thread, { success: true }); | ||
|
||
return true; | ||
} | ||
|
||
hide(thread: CommentThread): void { | ||
this.fireEvent("comment-hidden", thread); | ||
thread.dispose(); | ||
} | ||
|
||
// eslint-disable-next-line class-methods-use-this | ||
private fireEvent( | ||
event: string, | ||
thread: CommentThread, | ||
additionalProperties: Record<string, unknown> = {} | ||
): void { | ||
void fireEvent({ | ||
name: `code-review-${event}`, | ||
lineIndex: thread.range.start.line, | ||
file: thread.uri.path, | ||
lineCount: documentOf(thread)?.lineCount, | ||
...additionalProperties, | ||
}); | ||
} | ||
} | ||
|
||
function documentOf(thread: CommentThread): TextDocument | undefined { | ||
return workspace.textDocuments.find((doc) => doc.uri === thread.uri); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
import axios from "axios"; | ||
import tabnineExtensionProperties from "../globals/tabnineExtensionProperties"; | ||
|
||
const instance = axios.create({ | ||
baseURL: tabnineExtensionProperties.codeReviewBaseUrl, | ||
timeout: 30000, | ||
}); | ||
|
||
interface ExtensionsResponse { | ||
extensions: string[]; | ||
} | ||
|
||
export interface Range { | ||
start: number; | ||
end: number; | ||
} | ||
|
||
export interface SuggestionsRequest { | ||
filename: string; | ||
buffer: string; | ||
ranges: Range[]; | ||
threshold: string; | ||
} | ||
|
||
export interface Suggestion { | ||
value: string; | ||
classification: { type: string; description: string }; | ||
} | ||
|
||
export interface Suggestions { | ||
start: number; | ||
old_value: string; | ||
suggestions: Suggestion[]; | ||
} | ||
|
||
export interface SuggestionsResponse { | ||
filename: string; | ||
focus: Suggestions[]; | ||
} | ||
|
||
export async function supportedExtensions(): Promise<ExtensionsResponse> { | ||
return (await instance.get<ExtensionsResponse>("languages/extensions")).data; | ||
} | ||
|
||
export async function querySuggestions( | ||
payload: SuggestionsRequest | ||
): Promise<SuggestionsResponse> { | ||
return (await instance.post<SuggestionsResponse>("suggestions", payload)) | ||
.data; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
import * as vscode from "vscode"; | ||
import { Capability, isCapabilityEnabled } from "../capabilities/capabilities"; | ||
import addSuggestions from "./suggestions"; | ||
import DocumentThreads from "./DocumentThreads"; | ||
import TabnineComment from "./TabnineComment"; | ||
|
||
let activeThreads: DocumentThreads | null = null; | ||
|
||
export default function registerCodeReview(): void { | ||
const controller = vscode.comments.createCommentController( | ||
"tabnine.commentController", | ||
"" | ||
); | ||
controller.options = { | ||
placeHolder: "", | ||
prompt: "", | ||
}; | ||
|
||
vscode.commands.registerCommand( | ||
"Tabnine.hideSuggestion", | ||
(thread: vscode.CommentThread) => { | ||
const comment = thread.comments[0] as TabnineComment | undefined; | ||
|
||
if (comment) { | ||
comment.hide(thread); | ||
} | ||
} | ||
); | ||
|
||
vscode.commands.registerCommand( | ||
"Tabnine.applySuggestion", | ||
(thread: vscode.CommentThread) => { | ||
const comment = thread.comments[0] as TabnineComment | undefined; | ||
|
||
if (comment && comment.apply(thread)) { | ||
thread.dispose(); | ||
} | ||
} | ||
); | ||
|
||
vscode.window.onDidChangeActiveTextEditor(async () => { | ||
if (!isCapabilityEnabled(Capability.CODE_REVIEW)) return; | ||
|
||
const diffEditor = getActiveDiffEditor(); | ||
|
||
let newThreads = null; | ||
if (diffEditor) { | ||
newThreads = await addSuggestions( | ||
controller, | ||
diffEditor.newEditor.document, | ||
diffEditor.oldEditor.document | ||
); | ||
} | ||
|
||
if (activeThreads) { | ||
activeThreads.dispose(); | ||
} | ||
|
||
activeThreads = newThreads; | ||
}); | ||
} | ||
|
||
function getActiveDiffEditor(): { | ||
oldEditor: vscode.TextEditor; | ||
newEditor: vscode.TextEditor; | ||
} | null { | ||
const visibleEditors = vscode.window.visibleTextEditors; | ||
if (visibleEditors.length !== 2) return null; | ||
if ( | ||
visibleEditors[0].document.uri.path !== visibleEditors[1].document.uri.path | ||
) | ||
return null; | ||
|
||
const oldEditor = visibleEditors.find(isHeadGitEditor); | ||
const newEditor = visibleEditors.find( | ||
(editor) => editor.document.uri.scheme === "file" | ||
); | ||
|
||
if (oldEditor && newEditor) { | ||
return { oldEditor, newEditor }; | ||
} | ||
return null; | ||
} | ||
|
||
function isHeadGitEditor(editor: vscode.TextEditor): boolean { | ||
if (editor.document.uri.scheme === "git") { | ||
const query = JSON.parse(editor.document.uri.query) as { ref: string }; | ||
return query.ref === "HEAD" || query.ref === "~"; | ||
} | ||
|
||
return false; | ||
} |
Oops, something went wrong.