Ver código fonte

Improves changes hover accuracy & diff rendering

Adds hovers.changesDiff setting for line vs hunk diff
main
Eric Amodio 5 anos atrás
pai
commit
f625d37b00
15 arquivos alterados com 179 adições e 135 exclusões
  1. +1
    -0
      README.md
  2. +14
    -0
      package.json
  3. +36
    -22
      src/annotations/annotations.ts
  4. +4
    -3
      src/annotations/blameAnnotationProvider.ts
  5. +5
    -4
      src/annotations/gutterBlameAnnotationProvider.ts
  6. +4
    -3
      src/annotations/heatmapBlameAnnotationProvider.ts
  7. +7
    -6
      src/annotations/recentChangesAnnotationProvider.ts
  8. +2
    -1
      src/commands/diffLineWithWorking.ts
  9. +1
    -0
      src/config.ts
  10. +5
    -1
      src/git/git.ts
  11. +47
    -34
      src/git/gitService.ts
  12. +11
    -13
      src/git/models/diff.ts
  13. +3
    -3
      src/git/parsers/blameParser.ts
  14. +38
    -44
      src/git/parsers/diffParser.ts
  15. +1
    -1
      src/trackers/gitLineTracker.ts

+ 1
- 0
README.md Ver arquivo

@ -695,6 +695,7 @@ GitLens is highly customizable and provides many configuration settings to allow
| `gitlens.hovers.annotations.enabled` | Specifies whether to provide any hovers when showing blame annotations |
| `gitlens.hovers.annotations.over` | Specifies when to trigger hovers when showing blame annotations<br /><br />`annotation` - only shown when hovering over the line annotation<br />`line` - shown when hovering anywhere over the line |
| `gitlens.hovers.avatars` | Specifies whether to show avatar images in hovers |
| `gitlens.hovers.changesDiff` | Specifies whether to show just the changes to the line or the full set of related changes in the _changes (diff)_ hover<br /><br />`line` - Shows only the changes to the line<br /><br />`hunk` - Shows the full set of related changes |
| `gitlens.hovers.currentLine.changes` | Specifies whether to provide a _changes (diff)_ hover for the current line |
| `gitlens.hovers.currentLine.details` | Specifies whether to provide a _commit details_ hover for the current line |
| `gitlens.hovers.currentLine.enabled` | Specifies whether to provide any hovers for the current line |

+ 14
- 0
package.json Ver arquivo

@ -563,6 +563,20 @@
"markdownDescription": "Specifies whether to show avatar images in hovers",
"scope": "window"
},
"gitlens.hovers.changesDiff": {
"type": "string",
"default": "line",
"enum": [
"line",
"hunk"
],
"enumDescriptions": [
"Shows only the changes to the line",
"Shows the full set of related changes"
],
"markdownDescription": "Specifies whether to show just the changes to the line or the full set of related changes in the _changes (diff)_ hover",
"scope": "window"
},
"gitlens.hovers.detailsMarkdownFormat": {
"type": "string",
"default": "[${avatar} &nbsp;__${author}__](mailto:${email}), ${ago} &nbsp; _(${date})_ \n\n${message}\n\n${commands}",

+ 36
- 22
src/annotations/annotations.ts Ver arquivo

@ -14,8 +14,9 @@ import { Container } from '../container';
import {
CommitFormatOptions,
CommitFormatter,
GitBlameCommit,
GitCommit,
GitDiffChunkLine,
GitDiffHunkLine,
GitRemote,
GitService,
GitUri
@ -108,11 +109,11 @@ export class Annotations {
static getHoverDiffMessage(
commit: GitCommit,
uri: GitUri,
chunkLine: GitDiffChunkLine | undefined
hunkLine: GitDiffHunkLine | undefined
): MarkdownString | undefined {
if (chunkLine === undefined || commit.previousSha === undefined) return undefined;
if (hunkLine === undefined || commit.previousSha === undefined) return undefined;
const codeDiff = this.getCodeDiff(chunkLine);
const diff = this.getDiffFromHunkLine(hunkLine);
let message: string;
if (commit.isUncommitted) {
@ -121,12 +122,12 @@ export class Annotations {
GlyphChars.Dash
} &nbsp; [\`${commit.previousShortSha}\`](${ShowQuickCommitDetailsCommand.getMarkdownCommandArgs(
commit.previousSha!
)} "Show Commit Details") ${GlyphChars.ArrowLeftRightLong} _${uri.shortSha}_\n${codeDiff}`;
)} "Show Commit Details") ${GlyphChars.ArrowLeftRightLong} _${uri.shortSha}_\n${diff}`;
}
else {
message = `[\`Changes\`](${DiffWithCommand.getMarkdownCommandArgs(commit)} "Open Changes") &nbsp; ${
GlyphChars.Dash
} &nbsp; _uncommitted changes_\n${codeDiff}`;
} &nbsp; _uncommitted changes_\n${diff}`;
}
}
else {
@ -136,9 +137,7 @@ export class Annotations {
commit.previousSha!
)} "Show Commit Details") ${GlyphChars.ArrowLeftRightLong} [\`${
commit.shortSha
}\`](${ShowQuickCommitDetailsCommand.getMarkdownCommandArgs(
commit.sha
)} "Show Commit Details")\n${codeDiff}`;
}\`](${ShowQuickCommitDetailsCommand.getMarkdownCommandArgs(commit.sha)} "Show Commit Details")\n${diff}`;
}
const markdown = new MarkdownString(message);
@ -146,21 +145,36 @@ export class Annotations {
return markdown;
}
private static getCodeDiff(chunkLine: GitDiffChunkLine): string {
const previous = chunkLine.previous === undefined ? undefined : chunkLine.previous[0];
return `\`\`\`
- ${previous === undefined || previous.line === undefined ? '' : previous.line.trim()}
+ ${chunkLine.line === undefined ? '' : chunkLine.line.trim()}
\`\`\``;
private static getDiffFromHunkLine(hunkLine: GitDiffHunkLine): string {
if (Container.config.hovers.changesDiff === 'hunk') {
return `\`\`\`diff\n${hunkLine.hunk.diff}\n\`\`\``;
}
return `\`\`\`diff${hunkLine.previous === undefined ? '' : `\n-${hunkLine.previous.line}`}${
hunkLine.current === undefined ? '' : `\n+${hunkLine.current.line}`
}\n\`\`\``;
}
static async changesHover(commit: GitCommit, line: number, uri: GitUri): Promise<Partial<DecorationOptions>> {
const sha =
!commit.isUncommitted || (uri.sha !== undefined && GitService.isStagedUncommitted(uri.sha))
? commit.previousSha
: undefined;
const chunkLine = await Container.git.getDiffForLine(uri, line, sha);
const message = this.getHoverDiffMessage(commit, uri, chunkLine);
static async changesHover(
commit: GitBlameCommit,
editorLine: number,
uri: GitUri
): Promise<Partial<DecorationOptions>> {
let ref;
if (commit.isUncommitted) {
if (uri.sha !== undefined && GitService.isStagedUncommitted(uri.sha)) {
ref = uri.sha;
}
}
else {
ref = commit.sha;
}
const line = editorLine + 1;
const commitLine = commit.lines.find(l => l.line === line) || commit.lines[0];
const hunkLine = await Container.git.getDiffForLine(uri, commitLine.originalLine - 1, ref);
const message = this.getHoverDiffMessage(commit, uri, hunkLine);
return {
hoverMessage: message

+ 4
- 3
src/annotations/blameAnnotationProvider.ts Ver arquivo

@ -11,7 +11,7 @@ import {
TextEditorDecorationType
} from 'vscode';
import { Container } from '../container';
import { GitBlame, GitCommit, GitUri } from '../git/gitService';
import { GitBlame, GitBlameCommit, GitCommit, GitUri } from '../git/gitService';
import { Arrays, Iterables, log } from '../system';
import { GitDocumentState, TrackedDocument } from '../trackers/gitDocumentTracker';
import { AnnotationProviderBase } from './annotationProvider';
@ -88,7 +88,8 @@ export abstract class BlameAnnotationProviderBase extends AnnotationProviderBase
const highlightDecorationRanges = Arrays.filterMap(blame.lines, l =>
l.sha === sha
? this.editor.document.validateRange(new Range(l.line, 0, l.line, Number.MAX_SAFE_INTEGER))
? // editor lines are 0-based
this.editor.document.validateRange(new Range(l.line - 1, 0, l.line - 1, Number.MAX_SAFE_INTEGER))
: undefined
);
@ -255,7 +256,7 @@ export abstract class BlameAnnotationProviderBase extends AnnotationProviderBase
);
}
private async getCommitForHover(position: Position): Promise<GitCommit | undefined> {
private async getCommitForHover(position: Position): Promise<GitBlameCommit | undefined> {
if (Container.config.hovers.annotations.over !== 'line' && position.character !== 0) return undefined;
const blame = await this.getBlame();

+ 5
- 4
src/annotations/gutterBlameAnnotationProvider.ts Ver arquivo

@ -58,7 +58,8 @@ export class GutterBlameAnnotationProvider extends BlameAnnotationProviderBase {
}
for (const l of blame.lines) {
const line = l.line;
// editor lines are 0-based
const editorLine = l.line - 1;
if (previousSha === l.sha) {
if (gutter === undefined) continue;
@ -84,7 +85,7 @@ export class GutterBlameAnnotationProvider extends BlameAnnotationProviderBase {
compacted = true;
}
gutter.range = new Range(line, 0, line, 0);
gutter.range = new Range(editorLine, 0, editorLine, 0);
this.decorations.push(gutter);
@ -105,7 +106,7 @@ export class GutterBlameAnnotationProvider extends BlameAnnotationProviderBase {
if (gutter !== undefined) {
gutter = {
...gutter,
range: new Range(line, 0, line, 0)
range: new Range(editorLine, 0, editorLine, 0)
};
this.decorations.push(gutter);
@ -123,7 +124,7 @@ export class GutterBlameAnnotationProvider extends BlameAnnotationProviderBase {
Annotations.applyHeatmap(gutter, commit.date, computedHeatmap);
}
gutter.range = new Range(line, 0, line, 0);
gutter.range = new Range(editorLine, 0, editorLine, 0);
this.decorations.push(gutter);

+ 4
- 3
src/annotations/heatmapBlameAnnotationProvider.ts Ver arquivo

@ -31,13 +31,14 @@ export class HeatmapBlameAnnotationProvider extends BlameAnnotationProviderBase
const computedHeatmap = this.getComputedHeatmap(blame);
for (const l of blame.lines) {
const line = l.line;
// editor lines are 0-based
const editorLine = l.line - 1;
heatmap = decorationsMap[l.sha];
if (heatmap !== undefined) {
heatmap = {
...heatmap,
range: new Range(line, 0, line, 0)
range: new Range(editorLine, 0, editorLine, 0)
};
this.decorations.push(heatmap);
@ -49,7 +50,7 @@ export class HeatmapBlameAnnotationProvider extends BlameAnnotationProviderBase
if (commit === undefined) continue;
heatmap = Annotations.heatmap(commit, computedHeatmap, renderOptions) as DecorationOptions;
heatmap.range = new Range(line, 0, line, 0);
heatmap.range = new Range(editorLine, 0, editorLine, 0);
this.decorations.push(heatmap);
decorationsMap[l.sha] = heatmap;

+ 7
- 6
src/annotations/recentChangesAnnotationProvider.ts Ver arquivo

@ -32,7 +32,7 @@ export class RecentChangesAnnotationProvider extends AnnotationProviderBase {
const commit = await Container.git.getRecentLogCommitForFile(this._uri.repoPath, this._uri.fsPath);
if (commit === undefined) return false;
const diff = await Container.git.getDiffForFile(this._uri, commit.previousSha);
const diff = await Container.git.getDiffForFile(this._uri, commit.sha);
if (diff === undefined) return false;
let start = process.hrtime();
@ -42,14 +42,15 @@ export class RecentChangesAnnotationProvider extends AnnotationProviderBase {
this.decorations = [];
for (const chunk of diff.chunks) {
let count = chunk.currentPosition.start - 2;
for (const line of chunk.lines) {
if (line.line === undefined) continue;
for (const hunk of diff.hunks) {
// Subtract 2 because editor lines are 0-based and we will be adding 1 in the first iteration of the loop
let count = hunk.currentPosition.start - 2;
for (const line of hunk.lines) {
if (line.current === undefined) continue;
count++;
if (line.state === 'unchanged') continue;
if (line.current.state === 'unchanged') continue;
const range = this.editor.document.validateRange(
new Range(new Position(count, 0), new Position(count, Number.MAX_SAFE_INTEGER))

+ 2
- 1
src/commands/diffLineWithWorking.ts Ver arquivo

@ -59,7 +59,8 @@ export class DiffLineWithWorkingCommand extends ActiveEditorCommand {
previousSha: null,
previousFileName: null
});
args.line = blame.line.line + 1;
// editor lines are 0-based
args.line = blame.line.line - 1;
}
}
catch (ex) {

+ 1
- 0
src/config.ts Ver arquivo

@ -51,6 +51,7 @@ export interface Config {
over: 'line' | 'annotation';
};
avatars: boolean;
changesDiff: 'line' | 'hunk';
detailsMarkdownFormat: string;
enabled: boolean;
};

+ 5
- 1
src/git/git.ts Ver arquivo

@ -518,7 +518,7 @@ export class Git {
ref2?: string,
options: { encoding?: string; filter?: string } = {}
): Promise<string> {
const params = ['diff', '-M', '--no-ext-diff', '--minimal'];
const params = ['diff', '-M', '--no-ext-diff', '-U0', '--minimal'];
if (options.filter) {
params.push(`--diff-filter=${options.filter}`);
}
@ -866,6 +866,10 @@ export class Git {
}
}
static show_diff(repoPath: string, fileName: string, ref: string) {
return git<string>({ cwd: repoPath }, 'show', '--format=', '--minimal', '-U0', ref, '--', fileName);
}
static show_status(repoPath: string, fileName: string, ref: string) {
return git<string>({ cwd: repoPath }, 'show', '--name-status', '--format=', ref, '--', fileName);
}

+ 47
- 34
src/git/gitService.ts Ver arquivo

@ -43,7 +43,7 @@ import {
GitCommitType,
GitContributor,
GitDiff,
GitDiffChunkLine,
GitDiffHunkLine,
GitDiffParser,
GitDiffShortStat,
GitFile,
@ -139,7 +139,7 @@ export class GitService implements Disposable {
this._disposable && this._disposable.dispose();
}
get UseCaching() {
get useCaching() {
return Container.config.advanced.caching.enabled;
}
@ -749,7 +749,7 @@ export class GitService implements Disposable {
}
const doc = await Container.tracker.getOrAdd(uri);
if (this.UseCaching) {
if (this.useCaching) {
if (doc.state !== undefined) {
const cachedBlame = doc.state.get<CachedBlame>(key);
if (cachedBlame !== undefined) {
@ -832,7 +832,7 @@ export class GitService implements Disposable {
const key = `blame:${Strings.sha1(contents)}`;
const doc = await Container.tracker.getOrAdd(uri);
if (this.UseCaching) {
if (this.useCaching) {
if (doc.state !== undefined) {
const cachedBlame = doc.state.get<CachedBlame>(key);
if (cachedBlame !== undefined) {
@ -908,17 +908,17 @@ export class GitService implements Disposable {
@log()
async getBlameForLine(
uri: GitUri,
line: number,
editorLine: number, // editor lines are 0-based
options: { skipCache?: boolean } = {}
): Promise<GitBlameLine | undefined> {
if (!options.skipCache && this.UseCaching) {
if (!options.skipCache && this.useCaching) {
const blame = await this.getBlameForFile(uri);
if (blame === undefined) return undefined;
let blameLine = blame.lines[line];
let blameLine = blame.lines[editorLine];
if (blameLine === undefined) {
if (blame.lines.length !== line) return undefined;
blameLine = blame.lines[line - 1];
if (blame.lines.length !== editorLine) return undefined;
blameLine = blame.lines[editorLine - 1];
}
const commit = blame.commits.get(blameLine.sha);
@ -932,7 +932,7 @@ export class GitService implements Disposable {
};
}
const lineToBlame = line + 1;
const lineToBlame = editorLine + 1;
const fileName = uri.fsPath;
try {
@ -948,7 +948,7 @@ export class GitService implements Disposable {
return {
author: Iterables.first(blame.authors.values()),
commit: Iterables.first(blame.commits.values()),
line: blame.lines[line]
line: blame.lines[editorLine]
};
}
catch {
@ -963,18 +963,18 @@ export class GitService implements Disposable {
})
async getBlameForLineContents(
uri: GitUri,
line: number,
editorLine: number, // editor lines are 0-based
contents: string,
options: { skipCache?: boolean } = {}
): Promise<GitBlameLine | undefined> {
if (!options.skipCache && this.UseCaching) {
if (!options.skipCache && this.useCaching) {
const blame = await this.getBlameForFileContents(uri, contents);
if (blame === undefined) return undefined;
let blameLine = blame.lines[line];
let blameLine = blame.lines[editorLine];
if (blameLine === undefined) {
if (blame.lines.length !== line) return undefined;
blameLine = blame.lines[line - 1];
if (blame.lines.length !== editorLine) return undefined;
blameLine = blame.lines[editorLine - 1];
}
const commit = blame.commits.get(blameLine.sha);
@ -988,7 +988,7 @@ export class GitService implements Disposable {
};
}
const lineToBlame = line + 1;
const lineToBlame = editorLine + 1;
const fileName = uri.fsPath;
try {
@ -1005,7 +1005,7 @@ export class GitService implements Disposable {
return {
author: Iterables.first(blame.authors.values()),
commit: Iterables.first(blame.commits.values()),
line: blame.lines[line]
line: blame.lines[editorLine]
};
}
catch {
@ -1034,13 +1034,17 @@ export class GitService implements Disposable {
const lines = blame.lines.slice(range.start.line, range.end.line + 1);
const shas = new Set(lines.map(l => l.sha));
// ranges are 0-based
const startLine = range.start.line + 1;
const endLine = range.end.line + 1;
const authors: Map<string, GitAuthor> = new Map();
const commits: Map<string, GitBlameCommit> = new Map();
for (const c of blame.commits.values()) {
if (!shas.has(c.sha)) continue;
const commit = c.with({
lines: c.lines.filter(l => l.line >= range.start.line && l.line <= range.end.line)
lines: c.lines.filter(l => l.line >= startLine && l.line <= endLine)
});
commits.set(c.sha, commit);
@ -1165,13 +1169,9 @@ export class GitService implements Disposable {
}
@log()
async getDiffForFile(uri: GitUri, ref1?: string, ref2?: string): Promise<GitDiff | undefined> {
async getDiffForFile(uri: GitUri, ref1: string | undefined, ref2?: string): Promise<GitDiff | undefined> {
const cc = Logger.getCorrelationContext();
if (ref1 !== undefined && ref2 === undefined && uri.sha !== undefined) {
ref2 = uri.sha;
}
let key = 'diff';
if (ref1 !== undefined) {
key += `:${ref1}`;
@ -1181,7 +1181,7 @@ export class GitService implements Disposable {
}
const doc = await Container.tracker.getOrAdd(uri);
if (this.UseCaching) {
if (this.useCaching) {
if (doc.state !== undefined) {
const cachedDiff = doc.state.get<CachedDiff>(key);
if (cachedDiff !== undefined) {
@ -1233,7 +1233,14 @@ export class GitService implements Disposable {
const [file, root] = Git.splitPath(fileName, repoPath, false);
try {
const data = await Git.diff(root, file, ref1, ref2, { ...options, filter: 'M' });
let data;
if (ref1 !== undefined && ref2 === undefined && !GitService.isStagedUncommitted(ref1)) {
data = await Git.show_diff(root, file, ref1);
}
else {
data = await Git.diff(root, file, ref1, ref2, { ...options, filter: 'M' });
}
const diff = GitDiffParser.parse(data);
return diff;
}
@ -1259,18 +1266,24 @@ export class GitService implements Disposable {
@log()
async getDiffForLine(
uri: GitUri,
line: number,
ref1?: string,
editorLine: number, // editor lines are 0-based
ref1: string | undefined,
ref2?: string
): Promise<GitDiffChunkLine | undefined> {
): Promise<GitDiffHunkLine | undefined> {
try {
const diff = await this.getDiffForFile(uri, ref1, ref2);
let diff = await this.getDiffForFile(uri, ref1, ref2);
// If we didn't find a diff & ref1 is undefined (meaning uncommitted), check for a staged diff
if (diff === undefined && ref1 === undefined) {
diff = await this.getDiffForFile(uri, Git.stagedUncommittedSha, ref2);
}
if (diff === undefined) return undefined;
const chunk = diff.chunks.find(c => c.currentPosition.start <= line && c.currentPosition.end >= line);
if (chunk === undefined) return undefined;
const line = editorLine + 1;
const hunk = diff.hunks.find(c => c.currentPosition.start <= line && c.currentPosition.end >= line);
if (hunk === undefined) return undefined;
return chunk.lines[line - chunk.currentPosition.start + 1];
return hunk.lines[line - hunk.currentPosition.start];
}
catch (ex) {
return undefined;
@ -1480,7 +1493,7 @@ export class GitService implements Disposable {
}
const doc = await Container.tracker.getOrAdd(GitUri.fromFile(fileName, repoPath!, options.ref));
if (this.UseCaching && options.range === undefined) {
if (this.useCaching && options.range === undefined) {
if (doc.state !== undefined) {
const cachedLog = doc.state.get<CachedLog>(key);
if (cachedLog !== undefined) {

+ 11
- 13
src/git/models/diff.ts Ver arquivo

@ -6,26 +6,24 @@ export interface GitDiffLine {
state: 'added' | 'removed' | 'unchanged';
}
export interface GitDiffChunkLine extends GitDiffLine {
previous?: (GitDiffLine | undefined)[];
export interface GitDiffHunkLine {
hunk: GitDiffHunk;
current: GitDiffLine | undefined;
previous: GitDiffLine | undefined;
}
export class GitDiffChunk {
private _chunk: string | undefined;
private _lines: GitDiffChunkLine[] | undefined;
export class GitDiffHunk {
private _lines: GitDiffHunkLine[] | undefined;
constructor(
chunk: string,
public readonly diff: string,
public currentPosition: { start: number; end: number },
public previousPosition: { start: number; end: number }
) {
this._chunk = chunk;
}
) {}
get lines(): GitDiffChunkLine[] {
get lines(): GitDiffHunkLine[] {
if (this._lines === undefined) {
this._lines = GitDiffParser.parseChunk(this._chunk!);
this._chunk = undefined;
this._lines = GitDiffParser.parseHunk(this);
}
return this._lines;
@ -33,7 +31,7 @@ export class GitDiffChunk {
}
export interface GitDiff {
readonly chunks: GitDiffChunk[];
readonly hunks: GitDiffHunk[];
readonly diff?: string;
}

+ 3
- 3
src/git/parsers/blameParser.ts Ver arquivo

@ -55,8 +55,8 @@ export class GitBlameParser {
entry = {
author: undefined!,
sha: lineParts[0],
originalLine: parseInt(lineParts[1], 10) - 1,
line: parseInt(lineParts[2], 10) - 1,
originalLine: parseInt(lineParts[1], 10),
line: parseInt(lineParts[2], 10),
lineCount: parseInt(lineParts[3], 10)
};
@ -230,7 +230,7 @@ export class GitBlameParser {
}
commit.lines.push(line);
lines[line.line] = line;
lines[line.line - 1] = line;
}
}
}

+ 38
- 44
src/git/parsers/diffParser.ts Ver arquivo

@ -1,63 +1,70 @@
'use strict';
import { Iterables, Strings } from '../../system';
import { GitDiff, GitDiffChunk, GitDiffChunkLine, GitDiffLine, GitDiffShortStat, GitFile, GitFileStatus } from '../git';
import { Strings } from '../../system';
import { GitDiff, GitDiffHunk, GitDiffHunkLine, GitDiffLine, GitDiffShortStat, GitFile, GitFileStatus } from '../git';
const nameStatusDiffRegex = /^(.*?)\t(.*?)(?:\t(.*?))?$/gm;
const shortStatDiffRegex = /^\s*(\d+)\sfiles? changed(?:,\s+(\d+)\s+insertions?\(\+\))?(?:,\s+(\d+)\s+deletions?\(-\))?/;
const unifiedDiffRegex = /^@@ -([\d]+),([\d]+) [+]([\d]+),([\d]+) @@([\s\S]*?)(?=^@@)/gm;
const unifiedDiffRegex = /^@@ -([\d]+)(?:,([\d]+))? \+([\d]+)(?:,([\d]+))? @@(?:.*?)\n([\s\S]*?)(?=^@@)/gm;
export class GitDiffParser {
static parse(data: string, debug: boolean = false): GitDiff | undefined {
if (!data) return undefined;
const chunks: GitDiffChunk[] = [];
const hunks: GitDiffHunk[] = [];
let match: RegExpExecArray | null;
let chunk;
let hunk;
let currentStartStr;
let currentStart;
let currentCountStr;
let currentCount;
let previousStartStr;
let previousStart;
let previousCountStr;
let previousCount;
do {
match = unifiedDiffRegex.exec(`${data}\n@@`);
if (match == null) break;
// Stops excessive memory usage -- https://bugs.chromium.org/p/v8/issues/detail?id=2869
chunk = ` ${match[5]}`.substr(1);
currentStart = parseInt(match[3], 10);
previousStart = parseInt(match[1], 10);
hunk = ` ${match[5]}`.substr(1);
[, previousStartStr, previousCountStr, currentStartStr, currentCountStr] = match;
previousStart = parseInt(previousStartStr, 10);
previousCount = previousCountStr ? parseInt(previousCountStr, 10) : 0;
currentStart = parseInt(currentStartStr, 10);
currentCount = currentCountStr ? parseInt(currentCountStr, 10) : 0;
chunks.push(
new GitDiffChunk(
chunk,
hunks.push(
new GitDiffHunk(
hunk,
{
start: currentStart,
end: currentStart + parseInt(match[4], 10)
end: currentStart + currentCount
},
{
start: previousStart,
end: previousStart + parseInt(match[2], 10)
end: previousStart + previousCount
}
)
);
} while (match != null);
if (!chunks.length) return undefined;
if (!hunks.length) return undefined;
const diff: GitDiff = {
diff: debug ? data : undefined,
chunks: chunks
hunks: hunks
};
return diff;
}
static parseChunk(chunk: string): GitDiffChunkLine[] {
const lines = Iterables.skip(Strings.lines(chunk), 1);
static parseHunk(hunk: GitDiffHunk): GitDiffHunkLine[] {
const currentLines: (GitDiffLine | undefined)[] = [];
const previousLines: (GitDiffLine | undefined)[] = [];
let removed = 0;
for (const l of lines) {
for (const l of Strings.lines(hunk.diff)) {
switch (l[0]) {
case '+':
currentLines.push({
@ -97,35 +104,22 @@ export class GitDiffParser {
}
}
const chunkLines: GitDiffChunkLine[] = [];
while (removed > 0) {
removed--;
currentLines.push(undefined);
}
let chunkLine: GitDiffChunkLine | undefined = undefined;
let current: GitDiffLine | undefined = undefined;
const hunkLines: GitDiffHunkLine[] = [];
for (let i = 0; i < currentLines.length; i++) {
current = currentLines[i];
if (current === undefined) {
// Don't think we need to worry about this case because the diff will always have "padding" (i.e. unchanged lines) around each chunk
if (chunkLine === undefined) continue;
if (chunkLine.previous === undefined) {
chunkLine.previous = [previousLines[i]];
continue;
}
chunkLine.previous.push(previousLines[i]);
continue;
}
chunkLine = {
line: current.line,
state: current.state,
previous: [previousLines[i]]
};
chunkLines.push(chunkLine);
hunkLines.push({
hunk: hunk,
current: currentLines[i],
previous: previousLines[i]
});
}
return chunkLines;
return hunkLines;
}
static parseNameStatus(data: string, repoPath: string): GitFile[] | undefined {

+ 1
- 1
src/trackers/gitLineTracker.ts Ver arquivo

@ -123,7 +123,7 @@ export class GitLineTracker extends LineTracker {
: await Container.git.getBlameForLine(trackedDocument.uri, lines[0]);
if (blameLine === undefined) return false;
this.setState(blameLine.line.line, new GitLineState(blameLine.commit));
this.setState(blameLine.line.line - 1, new GitLineState(blameLine.commit));
}
else {
const blame = editor.document.isDirty

Carregando…
Cancelar
Salvar