diff --git a/src/annotations/blameAnnotationProvider.ts b/src/annotations/blameAnnotationProvider.ts index eb70073..ccbcab2 100644 --- a/src/annotations/blameAnnotationProvider.ts +++ b/src/annotations/blameAnnotationProvider.ts @@ -160,7 +160,7 @@ export abstract class BlameAnnotationProviderBase extends AnnotationProviderBase await Promise.all([ providers.details ? this.getDetailsHoverMessage(commit, document) : undefined, providers.changes - ? Hovers.changesMessage(commit, await GitUri.fromUri(document.uri), position.line) + ? Hovers.changesMessage(commit, await GitUri.fromUri(document.uri), position.line, document) : undefined, ]) ).filter((m?: T): m is T => Boolean(m)); diff --git a/src/env/node/git/localGitProvider.ts b/src/env/node/git/localGitProvider.ts index 2e4875d..cddd2ae 100644 --- a/src/env/node/git/localGitProvider.ts +++ b/src/env/node/git/localGitProvider.ts @@ -1637,7 +1637,6 @@ export class LocalGitProvider implements GitProvider, Disposable { renames: true, similarityThreshold: this.container.config.advanced.similarityThreshold, }); - // } const diff = GitDiffParser.parse(data); return diff; @@ -1761,7 +1760,7 @@ export class LocalGitProvider implements GitProvider, Disposable { const hunk = diff.hunks.find(c => c.current.position.start <= line && c.current.position.end >= line); if (hunk == null) return undefined; - return hunk.lines[line - hunk.current.position.start]; + return hunk.lines[line - Math.min(hunk.current.position.start, hunk.previous.position.start)]; } catch (ex) { return undefined; } diff --git a/src/git/models/reference.ts b/src/git/models/reference.ts index 1dca9aa..e377523 100644 --- a/src/git/models/reference.ts +++ b/src/git/models/reference.ts @@ -2,8 +2,6 @@ import { GlyphChars } from '../../constants'; import { Container } from '../../container'; import { GitBranch } from './branch'; -const emptyStr = ''; - const rangeRegex = /^(\S*?)(\.\.\.?)(\S*)\s*$/; const shaLikeRegex = /(^[0-9a-f]{40}([\^@~:]\S*)?$)|(^[0]{40}(:|-)$)/; const shaRegex = /(^[0-9a-f]{40}$)|(^[0]{40}(:|-)$)/; @@ -13,7 +11,7 @@ const uncommittedRegex = /^[0]{40}(?:[\^@~:]\S*)?:?$/; const uncommittedStagedRegex = /^[0]{40}([\^@~]\S*)?:$/; function isMatch(regex: RegExp, ref: string | undefined) { - return ref == null || ref.length === 0 ? false : regex.test(ref); + return !ref ? false : regex.test(ref); } export namespace GitRevision { @@ -46,11 +44,11 @@ export namespace GitRevision { } export function isUncommitted(ref: string | undefined) { - return isMatch(uncommittedRegex, ref); + return ref === uncommitted || isMatch(uncommittedRegex, ref); } export function isUncommittedStaged(ref: string | undefined): boolean { - return isMatch(uncommittedStagedRegex, ref); + return ref === uncommittedStaged || isMatch(uncommittedStagedRegex, ref); } export function shorten( @@ -65,7 +63,7 @@ export namespace GitRevision { ) { if (ref === deletedOrMissing) return '(deleted)'; - if (ref == null || ref.length === 0) return strings.working ?? emptyStr; + if (!ref) return strings.working ?? ''; if (isUncommitted(ref)) { return isUncommittedStaged(ref) ? strings.uncommittedStaged ?? 'Index' diff --git a/src/git/parsers/diffParser.ts b/src/git/parsers/diffParser.ts index 0bc95d3..ce43465 100644 --- a/src/git/parsers/diffParser.ts +++ b/src/git/parsers/diffParser.ts @@ -37,14 +37,14 @@ export class GitDiffParser { // Stops excessive memory usage -- https://bugs.chromium.org/p/v8/issues/detail?id=2869 ` ${hunk}`.substr(1), { - count: currentCount, + count: currentCount === 0 ? 1 : currentCount, position: { start: currentStart, end: currentStart + (currentCount > 0 ? currentCount - 1 : 0), }, }, { - count: previousCount, + count: previousCount === 0 ? 1 : previousCount, position: { start: previousStart, end: previousStart + (previousCount > 0 ? previousCount - 1 : 0), @@ -65,8 +65,17 @@ export class GitDiffParser { @debug({ args: false, singleLine: true }) static parseHunk(hunk: GitDiffHunk): { lines: GitDiffHunkLine[]; state: 'added' | 'changed' | 'removed' } { - const currentLines: (GitDiffLine | undefined)[] = []; - const previousLines: (GitDiffLine | undefined)[] = []; + const currentStart = hunk.current.position.start; + const previousStart = hunk.previous.position.start; + + const currentLines: (GitDiffLine | undefined)[] = + currentStart > previousStart + ? new Array(currentStart - previousStart).fill(undefined, 0, currentStart - previousStart) + : []; + const previousLines: (GitDiffLine | undefined)[] = + previousStart > currentStart + ? new Array(previousStart - currentStart).fill(undefined, 0, previousStart - currentStart) + : []; let hasAddedOrChanged; let hasRemoved; @@ -120,7 +129,7 @@ export class GitDiffParser { const hunkLines: GitDiffHunkLine[] = []; - for (let i = 0; i < currentLines.length; i++) { + for (let i = 0; i < Math.max(currentLines.length, previousLines.length); i++) { hunkLines.push({ hunk: hunk, current: currentLines[i], diff --git a/src/hovers/hovers.ts b/src/hovers/hovers.ts index 44ffd60..0b572cc 100644 --- a/src/hovers/hovers.ts +++ b/src/hovers/hovers.ts @@ -1,4 +1,4 @@ -import { CancellationToken, MarkdownString } from 'vscode'; +import { CancellationToken, MarkdownString, TextDocument } from 'vscode'; import { hrtime } from '@env/hrtime'; import { DiffWithCommand, ShowQuickCommitCommand } from '../commands'; import { GlyphChars } from '../constants'; @@ -24,11 +24,13 @@ export namespace Hovers { commit: GitBlameCommit | GitLogCommit, uri: GitUri, editorLine: number, + document: TextDocument, ): Promise { const documentRef = uri.sha; - let hunkLine; - if (GitBlameCommit.is(commit)) { + async function getDiff() { + if (!GitBlameCommit.is(commit)) return undefined; + // TODO: Figure out how to optimize this let ref; if (commit.isUncommitted) { @@ -37,7 +39,9 @@ export namespace Hovers { } } else { ref = commit.previousSha; - if (ref == null) return undefined; + if (ref == null) { + return `\`\`\`diff\n+ ${document.lineAt(editorLine).text}\n\`\`\``; + } } const line = editorLine + 1; @@ -52,7 +56,7 @@ export namespace Hovers { editorLine = commitLine.line - 1; // TODO: Doesn't work with dirty files -- pass in editor? or contents? - hunkLine = await Container.instance.git.getDiffForLine(uri, editorLine, ref, documentRef); + let hunkLine = await Container.instance.git.getDiffForLine(uri, editorLine, ref, documentRef); // If we didn't find a diff & ref is undefined (meaning uncommitted), check for a staged diff if (hunkLine == null && ref == null) { @@ -63,11 +67,11 @@ export namespace Hovers { GitRevision.uncommittedStaged, ); } - } - if (hunkLine == null || commit.previousSha == null) return undefined; + return hunkLine != null ? getDiffFromHunkLine(hunkLine) : undefined; + } - const diff = getDiffFromHunkLine(hunkLine); + const diff = await getDiff(); let message; let previous; @@ -91,14 +95,16 @@ export namespace Hovers { previous = diffUris.previous.sha == null || diffUris.previous.isUncommitted - ? `_${GitRevision.shorten(diffUris.previous.sha, { + ? `  _${GitRevision.shorten(diffUris.previous.sha, { strings: { working: 'Working Tree', }, - })}_` - : `[$(git-commit) ${GitRevision.shorten( + })}_  ${GlyphChars.ArrowLeftRightLong}  ` + : `  [$(git-commit) ${GitRevision.shorten( + diffUris.previous.sha || '', + )}](${ShowQuickCommitCommand.getMarkdownCommandArgs( diffUris.previous.sha || '', - )}](${ShowQuickCommitCommand.getMarkdownCommandArgs(diffUris.previous.sha || '')} "Show Commit")`; + )} "Show Commit")  ${GlyphChars.ArrowLeftRightLong}  `; current = diffUris.current.sha == null || diffUris.current.isUncommitted @@ -116,16 +122,20 @@ export namespace Hovers { editorLine, )} "Open Changes")`; - previous = `[$(git-commit) ${commit.previousShortSha}](${ShowQuickCommitCommand.getMarkdownCommandArgs( - commit.previousSha, - )} "Show Commit")`; + if (commit.previousSha) { + previous = `  [$(git-commit) ${ + commit.previousShortSha + }](${ShowQuickCommitCommand.getMarkdownCommandArgs(commit.previousSha)} "Show Commit")  ${ + GlyphChars.ArrowLeftRightLong + } `; + } current = `[$(git-commit) ${commit.shortSha}](${ShowQuickCommitCommand.getMarkdownCommandArgs( commit.sha, )} "Show Commit")`; } - message = `${diff}\n---\n\nChanges  ${previous}  ${GlyphChars.ArrowLeftRightLong}  ${current}   |   ${message}`; + message = `${diff}\n---\n\nChanges${previous ?? ' added in '}${current}   |   ${message}`; const markdown = new MarkdownString(message, true); markdown.supportHtml = true; diff --git a/src/hovers/lineHoverController.ts b/src/hovers/lineHoverController.ts index 5b810f9..7692127 100644 --- a/src/hovers/lineHoverController.ts +++ b/src/hovers/lineHoverController.ts @@ -193,7 +193,12 @@ export class LineHoverController implements Disposable { const trackedDocument = await this.container.tracker.get(document); if (trackedDocument == null) return undefined; - const message = await Hovers.changesMessage(commit, trackedDocument.uri, position.line); + const message = await Hovers.changesMessage( + commit, + trackedDocument.uri, + position.line, + trackedDocument.document, + ); if (message == null) return undefined; return new Hover(message, range);