Skip to content

Commit bfa29b0

Browse files
committed
fix: edge cases
1 parent e80aaa8 commit bfa29b0

File tree

11 files changed

+380
-81
lines changed

11 files changed

+380
-81
lines changed

ext-src/commands/DiscardSuggestion.ts

+20-28
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import * as vscode from 'vscode';
22
import { CurrentQuestion, Analyze, Session, AnalyseMetaData } from '../state';
3-
import { GenerateDecorations } from '../helpers/GenerateDecorations';
3+
import { GenerateDecorations, decorationType } from '../helpers/GenerateDecorations';
44
import { FeedbackSuggestionPayload, feedbackService } from '../services';
55
import CONSTANTS from '../constants';
66
import Utils from '../utils';
@@ -45,6 +45,8 @@ export function activateDiscardCommand(context: vscode.ExtensionContext): void {
4545
return;
4646
}
4747

48+
const copyProblems = { ...problems };
49+
4850
const payload: FeedbackSuggestionPayload = {
4951
problemId,
5052
discarded: true,
@@ -57,40 +59,30 @@ export function activateDiscardCommand(context: vscode.ExtensionContext): void {
5759
_debug?.appendLine(err.message);
5860
}
5961

60-
problems[key] = {
61-
...problems[key],
62-
isDiscarded: true,
63-
};
62+
copyProblems[key].isDiscarded = true;
6463

6564
try {
66-
await analyzeState.set(problems);
65+
analyzeState.set(copyProblems).then(() => {
66+
const results: AnalyseMetaData[] = [];
67+
68+
for (const [, value] of Object.entries(copyProblems)) {
69+
if (!value.isDiscarded) {
70+
results.push(value);
71+
}
72+
}
73+
74+
const { decorations } = GenerateDecorations(results, editor);
75+
editor.setDecorations(decorationType, []);
76+
editor.setDecorations(decorationType, decorations);
77+
currentQuestion.clear();
78+
79+
return;
80+
});
6781
} catch (error: any) {
6882
_debug.appendLine(error);
6983

7084
return;
7185
}
72-
73-
const analyzeValue = analyzeState.get()?.value;
74-
75-
if (!analyzeValue) {
76-
_debug?.appendLine('Metabob: analyzeValue is undefined in Discard Suggestion');
77-
78-
return;
79-
}
80-
81-
// Map all non discarded problems to the results array
82-
const results: AnalyseMetaData[] = Object.keys(analyzeValue)
83-
.filter(localKey => !analyzeValue[key].isDiscarded || localKey === key)
84-
.map(key => analyzeValue[key]);
85-
86-
const decorations = GenerateDecorations(results, editor);
87-
editor.setDecorations(decorations.decorationType, []);
88-
editor.setDecorations(decorations.decorationType, decorations.decorations);
89-
currentQuestion.clear();
90-
91-
// TODO: Send current question update to webview
92-
93-
return;
9486
};
9587

9688
context.subscriptions.push(vscode.commands.registerCommand(command, commandHandler));

ext-src/events.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { EventEmitter } from 'vscode';
22

33
export interface AnalysisEvents {
4-
type: 'Analysis_Error' | 'Analysis_Completed' | 'FIX_SUGGESTION';
4+
type: 'Analysis_Error' | 'Analysis_Completed' | 'Analysis_Called_On_Save' | 'FIX_SUGGESTION';
55
data: any;
66
}
77

ext-src/extension.ts

+85-17
Original file line numberDiff line numberDiff line change
@@ -74,23 +74,6 @@ export function activate(context: vscode.ExtensionContext): void {
7474
debugChannel.appendLine(`Metabob: ${error}`);
7575
}
7676

77-
// Analyze on Save functionality is only ran if the user enabled it.
78-
if (analyzeDocumentOnSaveConfig && analyzeDocumentOnSaveConfig === true) {
79-
context.subscriptions.push(
80-
vscode.workspace.onDidSaveTextDocument(document => {
81-
// Will check if the current document is valid code file.
82-
if (Util.isValidDocument(document)) {
83-
AnalyzeDocumentOnSave(
84-
{
85-
document,
86-
},
87-
context,
88-
);
89-
}
90-
}),
91-
);
92-
}
93-
9477
// If the user changes the global config from CMD + Shift + P -> User Setting -> Metabob
9578
// Then, we would update global state or reload the application
9679
context.subscriptions.push(
@@ -143,6 +126,91 @@ export function activate(context: vscode.ExtensionContext): void {
143126

144127
const extensionEventEmitter = getExtensionEventEmitter();
145128

129+
// Analyze on Save functionality is only ran if the user enabled it.
130+
context.subscriptions.push(
131+
vscode.workspace.onDidSaveTextDocument(document => {
132+
// Will check if the current document is valid code file.
133+
if (analyzeDocumentOnSaveConfig && analyzeDocumentOnSaveConfig === true) {
134+
if (!Util.isValidDocument) {
135+
return;
136+
}
137+
138+
AnalyzeDocumentOnSave(
139+
{
140+
document,
141+
},
142+
context,
143+
);
144+
extensionEventEmitter.fire({
145+
type: 'Analysis_Called_On_Save',
146+
data: {},
147+
});
148+
}
149+
}),
150+
);
151+
152+
context.subscriptions.push(
153+
vscode.workspace.onDidCloseTextDocument(() => {
154+
extensionEventEmitter.fire({
155+
type: 'Analysis_Completed',
156+
data: {},
157+
});
158+
}),
159+
);
160+
context.subscriptions.push(
161+
vscode.workspace.onDidOpenTextDocument(() => {
162+
const currentEditor = vscode.window.activeTextEditor;
163+
if (!currentEditor) return;
164+
165+
if (!Util.isValidDocument(currentEditor.document)) {
166+
return;
167+
}
168+
169+
const documentMetaData = Util.extractMetaDataFromDocument(currentEditor.document);
170+
171+
const filename: string | undefined = documentMetaData.relativePath.split('/').pop();
172+
173+
if (!filename) return;
174+
175+
const analyzeState = new Analyze(context);
176+
177+
const analyzeValue = analyzeState.get()?.value;
178+
179+
if (!analyzeValue) return;
180+
181+
const results: AnalyseMetaData[] = [];
182+
const analzeResultsOfCurrentFile: AnalyzeState = {};
183+
184+
for (const [key, value] of Object.entries(analyzeValue)) {
185+
const splitString: string | undefined = key.split('@@')[0];
186+
if (splitString === undefined) continue;
187+
188+
if (splitString === filename && value.isDiscarded === false) {
189+
results.push(value);
190+
191+
analzeResultsOfCurrentFile[key] = value;
192+
}
193+
}
194+
195+
if (results.length === 0) {
196+
extensionEventEmitter.fire({
197+
type: 'Analysis_Completed',
198+
data: analzeResultsOfCurrentFile,
199+
});
200+
201+
return;
202+
}
203+
204+
const { decorations } = GenerateDecorations(results, currentEditor);
205+
206+
currentEditor.setDecorations(decorationType, []);
207+
currentEditor.setDecorations(decorationType, decorations);
208+
extensionEventEmitter.fire({
209+
type: 'Analysis_Completed',
210+
data: { ...analzeResultsOfCurrentFile },
211+
});
212+
}),
213+
);
146214
context.subscriptions.push(
147215
vscode.window.onDidChangeActiveTextEditor(currentEditor => {
148216
if (!currentEditor) return;

ext-src/providers/recommendation.provider.ts

+79-15
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,9 @@ import {
1616
} from 'vscode';
1717
import { Configuration, CreateChatCompletionRequest, OpenAIApi } from 'openai';
1818
import { explainService, ExplainProblemPayload, SuggestRecomendationPayload } from '../services';
19-
import { CurrentQuestion, CurrentQuestionState, Session } from '../state';
19+
import { CurrentQuestion, CurrentQuestionState, Session, Analyze, AnalyseMetaData } from '../state';
2020
import { BackendService, GetChatGPTToken } from '../config';
21-
import { GenerateDecorations } from '../helpers';
21+
import { GenerateDecorations, decorationType } from '../helpers';
2222
import { DiscardCommandHandler, EndorseCommandHandler } from '../commands';
2323
import CONSTANTS from '../constants';
2424
import Util from '../utils';
@@ -31,6 +31,7 @@ export class RecommendationWebView implements WebviewViewProvider {
3131
private readonly extensionURI: Uri;
3232
private readonly extensionContext: ExtensionContext;
3333
private extensionEventEmitter: EventEmitter<AnalysisEvents>;
34+
private eventEmitterQueue: Array<AnalysisEvents> = [];
3435

3536
constructor(
3637
extensionPath: string,
@@ -86,6 +87,29 @@ export class RecommendationWebView implements WebviewViewProvider {
8687
return;
8788
}
8889

90+
let interval: NodeJS.Timeout | undefined = undefined;
91+
92+
if (!this._view.visible) {
93+
this.eventEmitterQueue.push(event);
94+
interval = setInterval(() => {
95+
if (this?._view === null || this?._view === undefined || !this?._view.webview) {
96+
return;
97+
}
98+
99+
if (!this._view.visible) {
100+
return;
101+
}
102+
103+
const latestEvent = this.eventEmitterQueue.pop();
104+
if (latestEvent) {
105+
this?._view?.webview?.postMessage(latestEvent);
106+
}
107+
108+
this.eventEmitterQueue = [];
109+
clearInterval(interval);
110+
}, 500);
111+
}
112+
89113
this._view.webview.postMessage(event);
90114
});
91115
}
@@ -286,7 +310,7 @@ export class RecommendationWebView implements WebviewViewProvider {
286310
const comment = `\t\t#${input}`;
287311
const position = new Position(startLine - 1, 0); // convert line number to position
288312
editor.edit((editBuilder: TextEditorEdit) => {
289-
editBuilder.insert(position, comment + '\n');
313+
editBuilder.replace(position, comment + '\n');
290314
});
291315
}
292316

@@ -326,18 +350,56 @@ export class RecommendationWebView implements WebviewViewProvider {
326350
throw new Error('handleApplyRecommendation: Editor or Init Data is undefined');
327351
}
328352

329-
const startLine = initData.vuln.startLine;
330-
const endLine = initData.vuln.endLine;
331-
const comment = `${input.replace('```', '')}`;
353+
debugChannel.appendLine('here1');
354+
const setAnalyzeState = new Analyze(this.extensionContext);
355+
const getanalyzeState = new Analyze(this.extensionContext).get()?.value;
332356

333-
const data = initData.vuln;
334-
const start = new Position(startLine - 1, 0); // convert line number to position
335-
const end = new Position(endLine, 0); // convert line number to position
336-
const range = new Range(start, end);
337-
editor.edit((editBuilder: TextEditorEdit) => {
338-
const decorations = GenerateDecorations([{ ...data }], editor);
339-
editor.setDecorations(decorations.decorationType, []);
340-
editBuilder.replace(range, comment + '\n');
357+
debugChannel.appendLine('here2');
358+
359+
if (!getanalyzeState) {
360+
debugChannel.appendLine('here3');
361+
throw new Error('Analze is undefined');
362+
}
363+
debugChannel.appendLine('here4');
364+
365+
const copyAnalyzeValue = { ...getanalyzeState };
366+
367+
const key = `${initData.path}@@${initData.id}`;
368+
copyAnalyzeValue[key].isDiscarded = true;
369+
370+
const results: AnalyseMetaData[] = [];
371+
372+
debugChannel.appendLine('here5');
373+
374+
for (const [, value] of Object.entries(copyAnalyzeValue)) {
375+
if (!value.isDiscarded) {
376+
results.push(value);
377+
}
378+
}
379+
380+
debugChannel.appendLine('here6');
381+
382+
setAnalyzeState.set({ ...copyAnalyzeValue }).then(() => {
383+
debugChannel.appendLine('here7');
384+
385+
const startLine = initData.vuln.startLine;
386+
const endLine = initData.vuln.endLine;
387+
const comment = `${input.replace('```', '')}`;
388+
389+
const start = new Position(startLine - 1, 0); // convert line number to position
390+
const end = new Position(endLine, 0); // convert line number to position
391+
const range = new Range(start, end);
392+
393+
const { decorations } = GenerateDecorations(results, editor);
394+
395+
editor.setDecorations(decorationType, []);
396+
editor.setDecorations(decorationType, decorations);
397+
398+
debugChannel.appendLine('here8');
399+
400+
editor.edit((editBuilder: TextEditorEdit) => {
401+
editBuilder.replace(range, comment + '\n');
402+
});
341403
});
342404
}
343405

@@ -466,7 +528,9 @@ export class RecommendationWebView implements WebviewViewProvider {
466528
}
467529
try {
468530
this.handleApplyRecommendation(input, initData);
469-
} catch {
531+
} catch (error: any) {
532+
debugChannel.appendLine(`Metabob: Apply Recommendation Error ${JSON.stringify(error)}`);
533+
470534
this._view.webview.postMessage({
471535
type: 'applyRecommendation:Error',
472536
data: {},

ext-src/utils.ts

+8
Original file line numberDiff line numberDiff line change
@@ -118,4 +118,12 @@ export default class Utils {
118118

119119
return decor;
120120
}
121+
122+
static openFileInNewTab(filePath: string): Thenable<vscode.TextEditor | undefined> {
123+
const uri = vscode.Uri.file(filePath);
124+
125+
return vscode.workspace.openTextDocument(uri).then(document => {
126+
return vscode.window.showTextDocument(document, vscode.ViewColumn.One);
127+
});
128+
}
121129
}

0 commit comments

Comments
 (0)