diff --git a/.editorconfig b/.editorconfig index 4d582a0f31fc..69dfbc863399 100644 --- a/.editorconfig +++ b/.editorconfig @@ -4,7 +4,7 @@ root = true insert_final_newline = true end_of_line = lf charset = utf-8 -trim_trailing_whitespace = true +trim_trailing_whitespace = false indent_style = space indent_size = 4 diff --git a/vscode/src/chat/chat-view/chat-helpers.ts b/vscode/src/chat/chat-view/chat-helpers.ts index dcc22f013b83..866290776043 100644 --- a/vscode/src/chat/chat-view/chat-helpers.ts +++ b/vscode/src/chat/chat-view/chat-helpers.ts @@ -13,3 +13,11 @@ export function getChatPanelTitle(lastHumanText?: string, truncateTitle = true): // truncate title that is too long return text.length > 25 ? `${text.slice(0, 25).trim()}...` : text } + +export function chatHelper(hello: string): string { + return hello +} + +export function chatHelper2(message: string): string { + return message +} diff --git a/vscode/src/completions/context/retrievers/recent-user-actions/recent-edits-diff-helpers/auotedit-short-term-diff.ts b/vscode/src/completions/context/retrievers/recent-user-actions/recent-edits-diff-helpers/auotedit-short-term-diff.ts index 326127b1202c..5b175c92f84a 100644 --- a/vscode/src/completions/context/retrievers/recent-user-actions/recent-edits-diff-helpers/auotedit-short-term-diff.ts +++ b/vscode/src/completions/context/retrievers/recent-user-actions/recent-edits-diff-helpers/auotedit-short-term-diff.ts @@ -22,10 +22,19 @@ export class AutoeditWithShortTermDiffStrategy implements RecentEditsRetrieverDi public getDiffHunks(input: DiffCalculationInput): DiffHunk[] { const rawChanges = groupChangesForSimilarLinesTogether(input.changes) + const rawDiffHunks = this.getDiffHunksFromGroupedChanges(input, rawChanges) const changes = combineNonOverlappingLinesSchemaTogether(rawChanges) - this.logGroupedChanges(input.uri, input.oldContent, changes) - const allDiffHunks: DiffHunk[] = [] + const combinedDiffHunks = this.getDiffHunksFromGroupedChanges(input, changes) + + this.logRawDataPoints(input.uri.toString(), input.oldContent, rawDiffHunks, combinedDiffHunks) + return combinedDiffHunks + } + private getDiffHunksFromGroupedChanges( + input: DiffCalculationInput, + changes: TextDocumentChangeGroup[] + ): DiffHunk[] { + const allDiffHunks: DiffHunk[] = [] let oldContent = input.oldContent for (const changeList of changes) { const [diffHunk, newContent] = this.getDiffHunksForChanges( @@ -40,6 +49,32 @@ export class AutoeditWithShortTermDiffStrategy implements RecentEditsRetrieverDi return allDiffHunks } + private logRawDataPoints(uri: string, oldContent: string, rawDiffHunks: DiffHunk[], combinedDiffHunks: DiffHunk[]) { + const dirPath = '/Users/hiteshsagtani/Desktop/raw-diff-logs' + const fileName = uri.split('/').pop()?.split('.')[0] || 'document' + const logPath = uri.replace(/[^/\\]+$/, `${fileName}_raw.jsonl`) + const finalLogPath = path.join(dirPath, path.basename(logPath)) + const fs = require('fs') + + // Create directory if it doesn't exist + if (!fs.existsSync(dirPath)) { + fs.mkdirSync(dirPath, { recursive: true }) + } + + const logData = { + uri: uri.toString(), + oldContent, + rawDiffHunks, + combinedDiffHunks + } + // Append to file if it exists, create if it doesn't + fs.appendFileSync( + finalLogPath, + JSON.stringify(logData) + '\n', + { encoding: 'utf8' } + ) + } + private logGroupedChanges(uri: vscode.Uri, oldContent: string, changes: TextDocumentChangeGroup[]) { const fileName = uri.fsPath.split('/').pop()?.split('.')[0] || 'document' const logPath = uri.fsPath.replace(/[^/\\]+$/, `${fileName}_grouped.json`) diff --git a/vscode/src/completions/context/retrievers/recent-user-actions/recent-edits-diff-helpers/utils.test.ts b/vscode/src/completions/context/retrievers/recent-user-actions/recent-edits-diff-helpers/utils.test.ts index 2cdb911eda57..3f1979cdca20 100644 --- a/vscode/src/completions/context/retrievers/recent-user-actions/recent-edits-diff-helpers/utils.test.ts +++ b/vscode/src/completions/context/retrievers/recent-user-actions/recent-edits-diff-helpers/utils.test.ts @@ -3,12 +3,7 @@ import dedent from 'dedent' import { describe, expect, it } from 'vitest' import type * as vscode from 'vscode' import { getDiffsForContentChanges, getTextDocumentChangesForText } from './helper' -import { - applyTextDocumentChanges, - computeDiffWithLineNumbers, - groupChangesForSimilarLinesTogether, - groupConsecutiveItemsByPredicate, -} from './utils' +import {applyTextDocumentChanges, computeDiffWithLineNumbers, groupChangesForSimilarLinesTogether, groupConsecutiveItemsByPredicate, combineNonOverlappingLinesSchemaTogether} from './utils'; const processComputedDiff = (text: string) => { const lines = text.split('\n') @@ -16,7 +11,7 @@ const processComputedDiff = (text: string) => { return updatedText.split('\n').slice(3).join('\n') } -describe('groupChangesForSimilarLinesTogether', () => { +describe('groupChangesForLines', () => { it('handles multiple deletions across different lines', () => { const text = dedent` @@ -48,6 +43,19 @@ describe('groupChangesForSimilarLinesTogether', () => { -} " `) + const combinedChanges = combineNonOverlappingLinesSchemaTogether(result) + expect(combinedChanges.length).toBe(1) + const combinedDiffs = getDiffsForContentChanges(originalText, combinedChanges) + expect(processComputedDiff(combinedDiffs[0])).toMatchInlineSnapshot(` + " const a = 5; + -console.log('test'); + const data = 5; + -function test() { + - return true; + -} + " + `) + }) it('handles interleaved insertions and deletions', () => { @@ -74,13 +82,27 @@ describe('groupChangesForSimilarLinesTogether', () => { function test() { const x = 5; if (true) { - console.log(x); + console.log(x); } } ` - const { changes } = getTextDocumentChangesForText(text) + const { originalText, changes } = getTextDocumentChangesForText(text) const result = groupChangesForSimilarLinesTogether(changes) expect(result.length).toBe(2) + const combinedChanges = combineNonOverlappingLinesSchemaTogether(result) + expect(combinedChanges.length).toBe(1) + const combinedDiffs = getDiffsForContentChanges(originalText, combinedChanges) + expect(processComputedDiff(combinedDiffs[0])).toMatchInlineSnapshot(` + " function test() { + - + - + + const x = 5; + + if (true) { + + console.log(x); + + } + } + " + `) }) it('seperate line changes for non-continous changes on different lines', () => { @@ -114,6 +136,18 @@ describe('groupChangesForSimilarLinesTogether', () => { +const a = 5; " `) + const combinedChanges = combineNonOverlappingLinesSchemaTogether(result) + expect(combinedChanges.length).toBe(1) + const combinedDiffs = getDiffsForContentChanges(originalText, combinedChanges) + expect(processComputedDiff(combinedDiffs[0])).toMatchInlineSnapshot(` + "-console. + -data = + -const + +console.log('Hello, world!'); + +data = 'check' + +const a = 5; + " + `) }) it('same line changes with non-continous character typing', () => { diff --git a/vscode/src/completions/context/retrievers/recent-user-actions/recent-edits-diff-helpers/utils.ts b/vscode/src/completions/context/retrievers/recent-user-actions/recent-edits-diff-helpers/utils.ts index 164ac23618e5..25831bd4f4ca 100644 --- a/vscode/src/completions/context/retrievers/recent-user-actions/recent-edits-diff-helpers/utils.ts +++ b/vscode/src/completions/context/retrievers/recent-user-actions/recent-edits-diff-helpers/utils.ts @@ -1,11 +1,11 @@ import { PromptString } from '@sourcegraph/cody-shared' import { displayPath } from '@sourcegraph/cody-shared/src/editor/displayPath' import { structuredPatch } from 'diff' -import type * as vscode from 'vscode' +import * as vscode from 'vscode' import type { TextDocumentChange } from './base' /** - * Represents a group of text document changes with their line range information. + * Represents a group of text document changes with their range information. * The grouped changes are consecutive changes made in the document that should be treated as a single entity when computing diffs. * * @example @@ -17,14 +17,14 @@ export interface TextDocumentChangeGroup { changes: TextDocumentChange[] /** - * The starting line number of the changes in this group + * The union of the inserted ranges of all changes in this group */ - changeStartLine: number + insertRange: vscode.Range /** - * The ending line number of the changes in this group + * The union of the replace ranges of all changes in this group */ - changeEndLine: number + replaceRange: vscode.Range } /** @@ -62,11 +62,10 @@ export function groupChangesForSimilarLinesTogether( } ) return groupedChanges.map(currentGroup => { - const range = getMinMaxRangeLines(currentGroup) return { changes: currentGroup, - changeStartLine: range[0], - changeEndLine: range[1], + insertRange: getRangeUnion(currentGroup.map(change => change.insertedRange)), + replaceRange: getRangeUnion(currentGroup.map(change => change.change.range)), } }) } @@ -96,33 +95,33 @@ export function combineNonOverlappingLinesSchemaTogether( } const combinedGroups = groupConsecutiveItemsByPredicate( groupedChanges, - (a: TextDocumentChangeGroup, b: TextDocumentChangeGroup) => { + (lastChange: TextDocumentChangeGroup, change: TextDocumentChangeGroup) => { return !doLineSpansOverlap( - a.changeStartLine, - a.changeEndLine, - b.changeStartLine, - b.changeEndLine + lastChange.insertRange.start.line, + lastChange.insertRange.end.line, + change.replaceRange.start.line, + change.replaceRange.end.line ) } ) return combinedGroups.map(changes => ({ changes: changes.flatMap(change => change.changes), - changeStartLine: Math.min(...changes.map(change => change.changeStartLine)), - changeEndLine: Math.max(...changes.map(change => change.changeEndLine)), + insertRange: getRangeUnion(changes.map(change => change.insertRange)), + replaceRange: getRangeUnion(changes.map(change => change.replaceRange)), })) } -function getMinMaxRangeLines(documentChanges: TextDocumentChange[]): [number, number] { - let minLine = Number.POSITIVE_INFINITY - let maxLine = Number.NEGATIVE_INFINITY - for (const change of documentChanges) { - const ranges = [change.change.range, change.insertedRange] - for (const range of ranges) { - minLine = Math.min(minLine, range.start.line) - maxLine = Math.max(maxLine, range.end.line) - } +function getRangeUnion(ranges: vscode.Range[]): vscode.Range { + if (ranges.length === 0) { + throw new Error('Cannot get union of empty ranges') + } + let start = ranges[0].start + let end = ranges[0].end + for (const range of ranges) { + start = start.isBefore(range.start) ? start : range.start + end = end.isAfter(range.end) ? end : range.end } - return [minLine, maxLine] + return new vscode.Range(start, end) } /**