diff --git a/README.md b/README.md index 5aebc20..cfac36b 100644 --- a/README.md +++ b/README.md @@ -29,6 +29,11 @@ None yet. ## Release Notes +### 0.0.5 + +Fixes issues where filename changes in history would cause diffs to fails +Removes CodeLens from fields and single-line properties to reduce visual noise + ### 0.0.4 Candidate for preview release on the vscode marketplace. diff --git a/package.json b/package.json index d66bc5c..0b0fe2b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "gitlens", - "version": "0.0.4", + "version": "0.0.5", "author": "Eric Amodio", "publisher": "eamodio", "engines": { diff --git a/src/commands.ts b/src/commands.ts index 3896765..549b81e 100644 --- a/src/commands.ts +++ b/src/commands.ts @@ -41,26 +41,22 @@ export class DiffWithPreviousCommand extends EditorCommand { super(Commands.DiffWithPrevious); } - execute(editor: TextEditor, edit: TextEditorEdit, uri?: Uri, sha?: string, compareWithSha?: string, line?: number) { + execute(editor: TextEditor, edit: TextEditorEdit, uri?: Uri, sha?: string, shaUri?: Uri, compareWithSha?: string, compareWithUri?: Uri, line?: number) { line = line || editor.selection.active.line; if (!sha) { - return this.git.getBlameForLine(uri.path, line) - .then(blame => commands.executeCommand(Commands.DiffWithPrevious, uri, blame.commit.sha, blame.commit.previousSha)); + return this.git.getBlameForLine(uri.fsPath, line) + .then(blame => commands.executeCommand(Commands.DiffWithPrevious, uri, blame.commit.sha, blame.commit.toUri(), blame.commit.previousSha, blame.commit.toPreviousUri(), line)); } if (!compareWithSha) { return window.showInformationMessage(`Commit ${sha} has no previous commit`); } - return Promise.all([this.git.getVersionedFile(uri.path, sha), this.git.getVersionedFile(uri.path, compareWithSha)]) - .then(values => { - const [source, compare] = values; - const fileName = basename(uri.path); - return commands.executeCommand(BuiltInCommands.Diff, Uri.file(compare), Uri.file(source), `${fileName} (${compareWithSha}) ↔ ${fileName} (${sha})`) - // TODO: Moving doesn't always seem to work -- or more accurately it seems like it moves down that number of lines from the current line - // which for a diff could be the first difference - .then(() => commands.executeCommand(BuiltInCommands.CursorMove, { to: 'down', value: line })); - }); + // TODO: Moving doesn't always seem to work -- or more accurately it seems like it moves down that number of lines from the current line + // which for a diff could be the first difference + return Promise.all([this.git.getVersionedFile(uri.fsPath, sha), this.git.getVersionedFile(uri.fsPath, compareWithSha)]) + .then(values => commands.executeCommand(BuiltInCommands.Diff, Uri.file(values[1]), Uri.file(values[0]), `${basename(compareWithUri.fsPath)} (${compareWithSha}) ↔ ${basename(shaUri.fsPath)} (${sha})`) + .then(() => commands.executeCommand(BuiltInCommands.CursorMove, { to: 'down', value: line }))); } } @@ -69,20 +65,18 @@ export class DiffWithWorkingCommand extends EditorCommand { super(Commands.DiffWithWorking); } - execute(editor: TextEditor, edit: TextEditorEdit, uri?: Uri, sha?: string, line?: number) { + execute(editor: TextEditor, edit: TextEditorEdit, uri?: Uri, sha?: string, shaUri?: Uri, line?: number) { line = line || editor.selection.active.line; if (!sha) { - return this.git.getBlameForLine(uri.path, line) - .then(blame => commands.executeCommand(Commands.DiffWithWorking, uri, blame.commit.sha)); + return this.git.getBlameForLine(uri.fsPath, line) + .then(blame => commands.executeCommand(Commands.DiffWithWorking, uri, blame.commit.sha, blame.commit.toUri(), line)); }; - return this.git.getVersionedFile(uri.path, sha).then(compare => { - const fileName = basename(uri.path); - return commands.executeCommand(BuiltInCommands.Diff, Uri.file(compare), uri, `${fileName} (${sha}) ↔ ${fileName} (index)`) - // TODO: Moving doesn't always seem to work -- or more accurately it seems like it moves down that number of lines from the current line - // which for a diff could be the first difference - .then(() => commands.executeCommand(BuiltInCommands.CursorMove, { to: 'down', value: line })); - }); + // TODO: Moving doesn't always seem to work -- or more accurately it seems like it moves down that number of lines from the current line + // which for a diff could be the first difference + return this.git.getVersionedFile(shaUri.fsPath, sha) + .then(compare => commands.executeCommand(BuiltInCommands.Diff, Uri.file(compare), uri, `${basename(shaUri.fsPath)} (${sha}) ↔ ${basename(uri.fsPath)} (index)`) + .then(() => commands.executeCommand(BuiltInCommands.CursorMove, { to: 'down', value: line }))); } } @@ -120,7 +114,7 @@ export class ShowBlameHistoryCommand extends EditorCommand { if (!uri) return; } - return this.git.getBlameLocations(uri.path, range).then(locations => { + return this.git.getBlameLocations(uri.fsPath, range).then(locations => { return commands.executeCommand(BuiltInCommands.ShowReferences, uri, position, locations); }); } diff --git a/src/gitBlameController.ts b/src/gitBlameController.ts index 43a6147..8e6f1dc 100644 --- a/src/gitBlameController.ts +++ b/src/gitBlameController.ts @@ -9,7 +9,7 @@ import * as moment from 'moment'; const blameDecoration: TextEditorDecorationType = window.createTextEditorDecorationType({ before: { color: '#5a5a5a', - margin: '0 1em 0 0', + margin: '0 1.75em 0 0', width: '5em' }, }); @@ -95,7 +95,7 @@ class GitBlameEditorController extends Disposable { constructor(private context: ExtensionContext, private git: GitProvider, public editor: TextEditor) { super(() => this.dispose()); - const fileName = this.editor.document.uri.path; + const fileName = this.editor.document.uri.fsPath; this._blame = this.git.getBlameForFile(fileName); const subscriptions: Disposable[] = []; diff --git a/src/gitCodeActionProvider.ts b/src/gitCodeActionProvider.ts index 9762d6e..cff92fe 100644 --- a/src/gitCodeActionProvider.ts +++ b/src/gitCodeActionProvider.ts @@ -21,7 +21,11 @@ export default class GitCodeActionProvider implements CodeActionProvider { actions.push({ title: `GitLens: Diff ${blame.commit.sha} with working tree`, command: Commands.DiffWithWorking, - arguments: [Uri.file(document.fileName), blame.commit.sha, blame.line.line] + arguments: [ + Uri.file(document.fileName), + blame.commit.sha, blame.commit.toUri(), + blame.line.line + ] }); } @@ -29,7 +33,12 @@ export default class GitCodeActionProvider implements CodeActionProvider { actions.push({ title: `GitLens: Diff ${blame.commit.sha} with previous ${blame.commit.previousSha}`, command: Commands.DiffWithPrevious, - arguments: [Uri.file(document.fileName), blame.commit.sha, blame.commit.previousSha, blame.line.line] + arguments: [ + Uri.file(document.fileName), + blame.commit.sha, blame.commit.toUri(), + blame.commit.previousSha, blame.commit.toPreviousUri(), + blame.line.line + ] }); } diff --git a/src/gitCodeLensProvider.ts b/src/gitCodeLensProvider.ts index 916f33e..0dc0773 100644 --- a/src/gitCodeLensProvider.ts +++ b/src/gitCodeLensProvider.ts @@ -5,7 +5,7 @@ import GitProvider, {IGitBlame, IGitBlameLines, IGitCommit} from './gitProvider' import * as moment from 'moment'; export class GitRecentChangeCodeLens extends CodeLens { - constructor(private git: GitProvider, public fileName: string, public blameRange: Range, range: Range) { + constructor(private git: GitProvider, public fileName: string, public symbolKind: SymbolKind, public blameRange: Range, range: Range) { super(range); } @@ -15,7 +15,7 @@ export class GitRecentChangeCodeLens extends CodeLens { } export class GitBlameCodeLens extends CodeLens { - constructor(private git: GitProvider, public fileName: string, public blameRange: Range, range: Range) { + constructor(private git: GitProvider, public fileName: string, public symbolKind: SymbolKind, public blameRange: Range, range: Range) { super(range); } @@ -54,8 +54,8 @@ export default class GitCodeLensProvider implements CodeLensProvider { // Check if we have a lens for the whole document -- if not add one if (!lenses.find(l => l.range.start.line === 0 && l.range.end.line === 0)) { const blameRange = document.validateRange(new Range(0, 1000000, 1000000, 1000000)); - lenses.push(new GitRecentChangeCodeLens(this.git, fileName, blameRange, new Range(0, 0, 0, blameRange.start.character))); - lenses.push(new GitBlameCodeLens(this.git, fileName, blameRange, new Range(0, 1, 0, blameRange.start.character))); + lenses.push(new GitRecentChangeCodeLens(this.git, fileName, SymbolKind.File, blameRange, new Range(0, 0, 0, blameRange.start.character))); + lenses.push(new GitBlameCodeLens(this.git, fileName, SymbolKind.File, blameRange, new Range(0, 1, 0, blameRange.start.character))); // if (this.hasGitHistoryExtension) { // lenses.push(new GitHistoryCodeLens(this.git.repoPath, fileName, new Range(0, 1, 0, blameRange.start.character))); // } @@ -65,6 +65,8 @@ export default class GitCodeLensProvider implements CodeLensProvider { }); } + foo: string; bar: number; + private _provideCodeLens(fileName: string, document: TextDocument, symbol: SymbolInformation, lenses: CodeLens[]): void { let multiline = false; switch (symbol.kind) { @@ -76,19 +78,19 @@ export default class GitCodeLensProvider implements CodeLensProvider { case SymbolKind.Method: case SymbolKind.Function: case SymbolKind.Enum: - multiline = true; + // HACK for Omnisharp, since it doesn't return full ranges + multiline = fileName.endsWith('.cs') || (symbol.location.range.end.line - symbol.location.range.start.line) > 1; break; case SymbolKind.Property: multiline = (symbol.location.range.end.line - symbol.location.range.start.line) > 1; - break; - case SymbolKind.Field: - multiline = false; + if (!multiline) return; break; default: return; } const line = document.lineAt(symbol.location.range.start); + // Make sure there is only 1 lense per line if (lenses.length && lenses[lenses.length - 1].range.start.line === line.lineNumber) { return; } @@ -100,10 +102,10 @@ export default class GitCodeLensProvider implements CodeLensProvider { startChar += Math.floor(symbol.name.length / 2); } - lenses.push(new GitRecentChangeCodeLens(this.git, fileName, symbol.location.range, line.range.with(new Position(line.range.start.line, startChar)))); + lenses.push(new GitRecentChangeCodeLens(this.git, fileName, symbol.kind, symbol.location.range, line.range.with(new Position(line.range.start.line, startChar)))); startChar++; if (multiline) { - lenses.push(new GitBlameCodeLens(this.git, fileName, symbol.location.range, line.range.with(new Position(line.range.start.line, startChar)))); + lenses.push(new GitBlameCodeLens(this.git, fileName, symbol.kind, symbol.location.range, line.range.with(new Position(line.range.start.line, startChar)))); startChar++; } // if (this.hasGitHistoryExtension) { @@ -121,7 +123,7 @@ export default class GitCodeLensProvider implements CodeLensProvider { return lens.getBlame().then(blame => { const recentCommit = blame.commits.values().next().value; lens.command = { - title: `${recentCommit.author}, ${moment(recentCommit.date).fromNow()}`, // - lines(${lens.blameRange.start.line + 1}-${lens.blameRange.end.line + 1})`, + title: `${recentCommit.author}, ${moment(recentCommit.date).fromNow()}`, // - ${SymbolKind[lens.symbolKind]}(${lens.blameRange.start.line + 1}-${lens.blameRange.end.line + 1})`, command: Commands.ShowBlameHistory, arguments: [Uri.file(lens.fileName), lens.blameRange, lens.range.start] }; diff --git a/src/gitProvider.ts b/src/gitProvider.ts index 2c0476d..5570f1a 100644 --- a/src/gitProvider.ts +++ b/src/gitProvider.ts @@ -3,7 +3,7 @@ import {Disposable, ExtensionContext, languages, Location, Position, Range, Uri, import {DocumentSchemes, WorkspaceState} from './constants'; import GitCodeLensProvider from './gitCodeLensProvider'; import Git from './git'; -import {basename, dirname, extname} from 'path'; +import {basename, dirname, extname, join} from 'path'; import * as moment from 'moment'; import * as _ from 'lodash'; @@ -97,14 +97,7 @@ export default class GitProvider extends Disposable { authors.set(authorName, author); } - commit = { - sha, - fileName: fileName, - author: authorName, - date: moment(`${m[7]} ${m[8]}`, 'X Z').toDate(), - message: m[13], - lines: [] - }; + commit = new GitCommit(this.repoPath, sha, fileName, authorName, moment(`${m[7]} ${m[8]}`, 'X Z').toDate(), m[13]); const originalFileName = m[16]; if (!fileName.toLowerCase().endsWith(originalFileName.toLowerCase())) { @@ -231,9 +224,9 @@ export default class GitProvider extends Disposable { const locations: Array = []; Array.from(blame.commits.values()) .forEach((c, i) => { - const uri = this.toBlameUri(c, i + 1, commitCount, range); + const uri = c.toBlameUri(i + 1, commitCount, range); c.lines.forEach(l => locations.push(new Location(c.originalFileName - ? this.toBlameUri(c, i + 1, commitCount, range, c.originalFileName) + ? c.toBlameUri(i + 1, commitCount, range, c.originalFileName) : uri, new Position(l.originalLine, 0)))); }); @@ -299,38 +292,6 @@ export default class GitProvider extends Disposable { private _fromGitUri(uri: Uri): T { return JSON.parse(uri.query) as T; } - - toBlameUri(commit: IGitCommit, index: number, commitCount: number, range: Range, originalFileName?: string) { - return this._toGitUri(DocumentSchemes.GitBlame, commit, commitCount, this._toGitBlameUriData(commit, index, range, originalFileName)); - } - - toGitUri(commit: IGitCommit, index: number, commitCount: number, originalFileName?: string) { - return this._toGitUri(DocumentSchemes.Git, commit, commitCount, this._toGitUriData(commit, index, originalFileName)); - } - - private _toGitUri(scheme: DocumentSchemes, commit: IGitCommit, commitCount: number, data: IGitUriData | IGitBlameUriData) { - const pad = n => ("0000000" + n).slice(-("" + commitCount).length); - const ext = extname(data.fileName); - const path = `${dirname(data.fileName)}/${commit.sha}: ${basename(data.fileName, ext)}${ext}`; - - // NOTE: Need to specify an index here, since I can't control the sort order -- just alphabetic or by file location - return Uri.parse(`${scheme}:${pad(data.index)}. ${commit.author}, ${moment(commit.date).format('MMM D, YYYY hh:MM a')} - ${path}?${JSON.stringify(data)}`); - } - - private _toGitUriData(commit: IGitCommit, index: number, originalFileName?: string): T { - const fileName = originalFileName || commit.fileName; - const data = { fileName: commit.fileName, sha: commit.sha, index: index } as T; - if (originalFileName) { - data.originalFileName = originalFileName; - } - return data; - } - - private _toGitBlameUriData(commit: IGitCommit, index: number, range: Range, originalFileName?: string) { - const data = this._toGitUriData(commit, index, originalFileName); - data.range = range; - return data; - } } export interface IGitBlame { @@ -370,6 +331,64 @@ export interface IGitCommit { originalFileName?: string; previousSha?: string; previousFileName?: string; + + toPreviousUri(): Uri; + toUri(): Uri; + + toBlameUri(index: number, commitCount: number, range: Range, originalFileName?: string); + toGitUri(index: number, commitCount: number, originalFileName?: string); +} + +class GitCommit implements IGitCommit { + lines: IGitCommitLine[]; + originalFileName?: string; + previousSha?: string; + previousFileName?: string; + + constructor(private repoPath: string, public sha: string, public fileName: string, public author: string, public date: Date, public message: string) { + this.lines = []; + } + + toPreviousUri(): Uri { + return this.previousFileName ? Uri.file(join(this.repoPath, this.previousFileName)) : this.toUri(); + } + + toUri(): Uri { + return Uri.file(join(this.repoPath, this.originalFileName || this.fileName)); + } + + toBlameUri(index: number, commitCount: number, range: Range, originalFileName?: string) { + return this._toGitUri(DocumentSchemes.GitBlame, commitCount, this._toGitBlameUriData(index, range, originalFileName)); + } + + toGitUri(index: number, commitCount: number, originalFileName?: string) { + return this._toGitUri(DocumentSchemes.Git, commitCount, this._toGitUriData(index, originalFileName)); + } + + private _toGitUri(scheme: DocumentSchemes, commitCount: number, data: IGitUriData | IGitBlameUriData) { + const pad = n => ("0000000" + n).slice(-("" + commitCount).length); + const ext = extname(data.fileName); + // const path = `${dirname(data.fileName)}/${commit.sha}: ${basename(data.fileName, ext)}${ext}`; + const path = `${dirname(data.fileName)}/${this.sha}${ext}`; + + // NOTE: Need to specify an index here, since I can't control the sort order -- just alphabetic or by file location + return Uri.parse(`${scheme}:${pad(data.index)}. ${this.author}, ${moment(this.date).format('MMM D, YYYY hh:MM a')} - ${path}?${JSON.stringify(data)}`); + } + + private _toGitUriData(index: number, originalFileName?: string): T { + const fileName = originalFileName || this.fileName; + const data = { fileName: this.fileName, sha: this.sha, index: index } as T; + if (originalFileName) { + data.originalFileName = originalFileName; + } + return data; + } + + private _toGitBlameUriData(index: number, range: Range, originalFileName?: string) { + const data = this._toGitUriData(index, originalFileName); + data.range = range; + return data; + } } export interface IGitCommitLine {