From 0f2f79fca7020c98976a73fba1ffde34db2bd871 Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Fri, 31 Aug 2018 23:16:47 -0400 Subject: [PATCH] Fixes #430 - Use content provider instead of tmp files (for text docs) --- CHANGELOG.md | 1 + src/codelens/gitCodeLensProvider.ts | 4 +- src/codelens/gitRevisionCodeLensProvider.ts | 91 ----------------------------- src/commands/common.ts | 19 +++--- src/commands/diffWithWorking.ts | 4 +- src/constants.ts | 12 +++- src/container.ts | 4 -- src/git/gitUri.ts | 15 +++-- src/git/models/repository.ts | 12 ++-- src/gitContentProvider.ts | 8 ++- src/gitService.ts | 20 ++++--- src/trackers/documentTracker.ts | 6 +- 12 files changed, 57 insertions(+), 139 deletions(-) delete mode 100644 src/codelens/gitRevisionCodeLensProvider.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 6b70f85..426c7ae 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p ### Fixed - Fixes [#405](https://github.com/eamodio/vscode-gitlens/issues/405) - Secondary, blank repository appears repeatedly in gitExplorer view +- Fixes [#430](https://github.com/eamodio/vscode-gitlens/issues/430) - File revisions can end up being parsed by language servers (causing errors and warnings, etc) - Fixes issues with git log caching ### Removed diff --git a/src/codelens/gitCodeLensProvider.ts b/src/codelens/gitCodeLensProvider.ts index c3bbbb0..e37f76c 100644 --- a/src/codelens/gitCodeLensProvider.ts +++ b/src/codelens/gitCodeLensProvider.ts @@ -222,7 +222,7 @@ export class GitCodeLensProvider implements CodeLensProvider { gitUri.getFilename(), SymbolKind.File, '', - new Location(gitUri.fileUri(), new Range(0, 0, 0, blameRange.start.character)) + new Location(gitUri.documentUri(), new Range(0, 0, 0, blameRange.start.character)) ); lenses.push( new GitRecentChangeCodeLens( @@ -249,7 +249,7 @@ export class GitCodeLensProvider implements CodeLensProvider { gitUri.getFilename(), SymbolKind.File, '', - new Location(gitUri.fileUri(), new Range(0, 1, 0, blameRange.start.character)) + new Location(gitUri.documentUri(), new Range(0, 1, 0, blameRange.start.character)) ); lenses.push( new GitAuthorsCodeLens( diff --git a/src/codelens/gitRevisionCodeLensProvider.ts b/src/codelens/gitRevisionCodeLensProvider.ts deleted file mode 100644 index c7a56ad..0000000 --- a/src/codelens/gitRevisionCodeLensProvider.ts +++ /dev/null @@ -1,91 +0,0 @@ -'use strict'; -import { CancellationToken, CodeLens, CodeLensProvider, DocumentSelector, Range, TextDocument, Uri } from 'vscode'; -import { Commands, DiffWithPreviousCommandArgs, DiffWithWorkingCommandArgs } from '../commands'; -import { DocumentSchemes } from '../constants'; -import { Container } from '../container'; -import { GitCommit, GitUri } from '../gitService'; - -export class GitDiffWithWorkingCodeLens extends CodeLens { - constructor( - public readonly fileName: string, - public readonly commit: GitCommit, - range: Range - ) { - super(range); - } -} - -export class GitDiffWithPreviousCodeLens extends CodeLens { - constructor( - public readonly fileName: string, - public readonly commit: GitCommit, - range: Range - ) { - super(range); - } -} - -export class GitRevisionCodeLensProvider implements CodeLensProvider { - static selector: DocumentSelector = { scheme: DocumentSchemes.GitLensGit }; - - async provideCodeLenses(document: TextDocument, token: CancellationToken): Promise { - const gitUri = GitUri.fromRevisionUri(document.uri); - - const lenses: CodeLens[] = []; - - const commit = await Container.git.getLogCommitForFile(gitUri.repoPath, gitUri.fsPath, { - ref: gitUri.sha, - firstIfNotFound: true - }); - if (commit === undefined) return lenses; - - if (commit.previousSha) { - lenses.push(new GitDiffWithPreviousCodeLens(commit.previousUri.fsPath, commit, new Range(0, 0, 0, 1))); - } - lenses.push(new GitDiffWithWorkingCodeLens(commit.uri.fsPath, commit, new Range(0, 1, 0, 2))); - - return lenses; - } - - resolveCodeLens(lens: CodeLens, token: CancellationToken): Thenable { - if (lens instanceof GitDiffWithWorkingCodeLens) return this._resolveDiffWithWorkingTreeCodeLens(lens, token); - if (lens instanceof GitDiffWithPreviousCodeLens) return this._resolveGitDiffWithPreviousCodeLens(lens, token); - return Promise.reject(undefined); - } - - _resolveDiffWithWorkingTreeCodeLens( - lens: GitDiffWithWorkingCodeLens, - token: CancellationToken - ): Thenable { - lens.command = { - title: `Compare Revision (${lens.commit.shortSha}) with Working`, - command: Commands.DiffWithWorking, - arguments: [ - Uri.file(lens.fileName), - { - commit: lens.commit, - line: lens.range.start.line - } as DiffWithWorkingCommandArgs - ] - }; - return Promise.resolve(lens); - } - - _resolveGitDiffWithPreviousCodeLens( - lens: GitDiffWithPreviousCodeLens, - token: CancellationToken - ): Thenable { - lens.command = { - title: `Compare Revision (${lens.commit.shortSha}) with Previous (${lens.commit.previousShortSha})`, - command: Commands.DiffWithPrevious, - arguments: [ - Uri.file(lens.fileName), - { - commit: lens.commit, - line: lens.range.start.line - } as DiffWithPreviousCommandArgs - ] - }; - return Promise.resolve(lens); - } -} diff --git a/src/commands/common.ts b/src/commands/common.ts index 593750a..983408d 100644 --- a/src/commands/common.ts +++ b/src/commands/common.ts @@ -13,7 +13,7 @@ import { window, workspace } from 'vscode'; -import { BuiltInCommands, DocumentSchemes, ImageExtensions } from '../constants'; +import { BuiltInCommands, DocumentSchemes, ImageMimetypes } from '../constants'; import { Container } from '../container'; import { GitBranch, GitCommit, GitRemote, GitUri } from '../gitService'; import { Logger } from '../logger'; @@ -394,21 +394,18 @@ export async function openEditor( const { rethrow, ...opts } = options; try { if (uri instanceof GitUri) { - uri = uri.fileUri({ noSha: true }); + uri = uri.documentUri({ noSha: true }); } - // TODO: revist this // This is a bit of an ugly hack, but I added it because there a bunch of call sites and toRevisionUri can't be easily made async because of its use in ctors - if (uri.scheme === DocumentSchemes.GitLensGit) { + if (uri.scheme === DocumentSchemes.GitLensGit && ImageMimetypes[path.extname(uri.fsPath)]) { const gitUri = GitUri.fromRevisionUri(uri); - if (ImageExtensions.includes(path.extname(gitUri.fsPath))) { - const uri = await Container.git.getVersionedFile(gitUri.repoPath, gitUri.fsPath, gitUri.sha); - if (uri !== undefined) { - await commands.executeCommand(BuiltInCommands.Open, uri); - - return undefined; - } + const imageUri = await Container.git.getVersionedFile(gitUri.repoPath, gitUri.fsPath, gitUri.sha); + if (imageUri !== undefined) { + await commands.executeCommand(BuiltInCommands.Open, imageUri); } + + return undefined; } const document = await workspace.openTextDocument(uri); diff --git a/src/commands/diffWithWorking.ts b/src/commands/diffWithWorking.ts index f023878..d8255a4 100644 --- a/src/commands/diffWithWorking.ts +++ b/src/commands/diffWithWorking.ts @@ -44,11 +44,11 @@ export class DiffWithWorkingCommand extends ActiveEditorCommand { repoPath: gitUri.repoPath, lhs: { sha: GitService.stagedUncommittedSha, - uri: gitUri.fileUri() + uri: gitUri.documentUri() }, rhs: { sha: '', - uri: gitUri.fileUri() + uri: gitUri.documentUri() }, line: args.line, showOptions: args.showOptions diff --git a/src/constants.ts b/src/constants.ts index 6b82f90..ad267e6 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -109,7 +109,17 @@ export enum GlobalState { GitLensVersion = 'gitlensVersion' } -export const ImageExtensions = ['.png', '.gif', '.jpg', '.jpeg', '.webp', '.tif', '.tiff', '.bmp']; +export const ImageMimetypes: { [key: string]: string } = { + '.png': 'image/png', + '.gif': 'image/gif', + '.jpg': 'image/jpeg', + '.jpeg': 'image/jpeg', + '.jpe': 'image/jpeg', + '.webp': 'image/webp', + '.tif': 'image/tiff', + '.tiff': 'image/tiff', + '.bmp': 'image/bmp' +}; export enum WorkspaceState { GitExplorerAutoRefresh = 'gitlens:gitExplorer:autoRefresh', diff --git a/src/container.ts b/src/container.ts index 65d470d..1d550d9 100644 --- a/src/container.ts +++ b/src/container.ts @@ -3,7 +3,6 @@ import { Disposable, ExtensionContext, languages, workspace } from 'vscode'; import { FileAnnotationController } from './annotations/fileAnnotationController'; import { LineAnnotationController } from './annotations/lineAnnotationController'; import { CodeLensController } from './codelens/codeLensController'; -import { GitRevisionCodeLensProvider } from './codelens/gitRevisionCodeLensProvider'; import { configuration, IConfig } from './configuration'; import { GitContentProvider } from './gitContentProvider'; import { GitService } from './gitService'; @@ -69,9 +68,6 @@ export class Container { context.subscriptions.push( workspace.registerTextDocumentContentProvider(GitContentProvider.scheme, new GitContentProvider()) ); - context.subscriptions.push( - languages.registerCodeLensProvider(GitRevisionCodeLensProvider.selector, new GitRevisionCodeLensProvider()) - ); } private static _codeLensController: CodeLensController; diff --git a/src/git/gitUri.ts b/src/git/gitUri.ts index 80b59b4..5e67c9c 100644 --- a/src/git/gitUri.ts +++ b/src/git/gitUri.ts @@ -33,7 +33,6 @@ interface UriEx { export class GitUri extends ((Uri as any) as UriEx) { repoPath?: string; sha?: string; - versionedPath?: string; constructor(uri?: Uri); @@ -94,16 +93,16 @@ export class GitUri extends ((Uri as any) as UriEx) { return this.sha && GitService.shortenSha(this.sha); } - equals(uri: Uri | undefined) { - if (!UriComparer.equals(this, uri)) return false; + documentUri(options: { noSha?: boolean; useVersionedPath?: boolean } = {}) { + if (options.useVersionedPath && this.versionedPath !== undefined) return Uri.file(this.versionedPath); - return this.sha === (uri instanceof GitUri ? uri.sha : undefined); + return this.scheme === 'file' ? Uri.file(!options.noSha && this.sha ? this.path : this.fsPath) : this; } - fileUri(options: { noSha?: boolean; useVersionedPath?: boolean } = {}) { - if (options.useVersionedPath && this.versionedPath !== undefined) return Uri.file(this.versionedPath); + equals(uri: Uri | undefined) { + if (!UriComparer.equals(this, uri)) return false; - return Uri.file(!options.noSha && this.sha ? this.path : this.fsPath); + return this.sha === (uri instanceof GitUri ? uri.sha : undefined); } getDirectory(relativeTo?: string): string { @@ -314,7 +313,7 @@ export class GitUri extends ((Uri as any) as UriEx) { const parsed = path.parse(fileName); return Uri.parse( - `${DocumentSchemes.GitLensGit}:${path.join(parsed.dir, parsed.name)}:${shortSha}${ + `${DocumentSchemes.GitLensGit}:${path.join(parsed.dir, parsed.name)} (${shortSha})${ parsed.ext }?${JSON.stringify(data)}` ); diff --git a/src/git/models/repository.ts b/src/git/models/repository.ts index bec6b06..5478659 100644 --- a/src/git/models/repository.ts +++ b/src/git/models/repository.ts @@ -218,13 +218,13 @@ export class Repository implements Disposable { } } - containsUri(uri: Uri) { - if (uri instanceof GitUri) { - uri = uri.repoPath !== undefined ? Uri.file(uri.repoPath) : uri.fileUri(); - } + // containsUri(uri: Uri) { + // if (uri instanceof GitUri) { + // uri = uri.repoPath !== undefined ? Uri.file(uri.repoPath) : uri.documentUri(); + // } - return this.folder === workspace.getWorkspaceFolder(uri); - } + // return this.folder === workspace.getWorkspaceFolder(uri); + // } getBranch(): Promise { if (this._branch === undefined) { diff --git a/src/gitContentProvider.ts b/src/gitContentProvider.ts index c6da389..966f075 100644 --- a/src/gitContentProvider.ts +++ b/src/gitContentProvider.ts @@ -1,8 +1,7 @@ 'use strict'; import * as path from 'path'; -import { CancellationToken, TextDocumentContentProvider, Uri, window } from 'vscode'; +import { CancellationToken, TextDocumentContentProvider, Uri, window, workspace } from 'vscode'; import { DocumentSchemes } from './constants'; -import { Container } from './container'; import { GitService, GitUri } from './gitService'; import { Logger } from './logger'; @@ -14,7 +13,10 @@ export class GitContentProvider implements TextDocumentContentProvider { if (!gitUri.repoPath || gitUri.sha === GitService.deletedSha) return ''; try { - return await Container.git.getVersionedFileText(gitUri.repoPath, gitUri.fsPath, gitUri.sha || 'HEAD'); + const document = await workspace.openTextDocument( + Uri.parse(`git:/${gitUri.fsPath}?${JSON.stringify({ path: gitUri.fsPath, ref: gitUri.sha || 'HEAD' })}`) + ); + return document.getText(); } catch (ex) { Logger.error(ex, 'GitContentProvider', 'getVersionedFileText'); diff --git a/src/gitService.ts b/src/gitService.ts index bd8a5a2..22bb5c4 100644 --- a/src/gitService.ts +++ b/src/gitService.ts @@ -18,7 +18,7 @@ import { } from 'vscode'; import { GitExtension } from './@types/git'; import { configuration, IRemotesConfig } from './configuration'; -import { CommandContext, DocumentSchemes, GlyphChars, setCommandContext } from './constants'; +import { CommandContext, DocumentSchemes, GlyphChars, ImageMimetypes, setCommandContext } from './constants'; import { Container } from './container'; import { CommitFormatting, @@ -1652,15 +1652,19 @@ export class GitService implements Disposable { return undefined; } - const file = await Git.getVersionedFile(repoPath, fileName, sha); - if (file === undefined) return undefined; + if (ImageMimetypes[path.extname(fileName)]) { + const file = await Git.getVersionedFile(repoPath, fileName, sha); + if (file === undefined) return undefined; - this._versionedUriCache.set( - GitUri.toKey(file), - new GitUri(Uri.file(fileName), { sha: sha, repoPath: repoPath!, versionedPath: file }) - ); + this._versionedUriCache.set( + GitUri.toKey(file), + new GitUri(Uri.file(fileName), { sha: sha, repoPath: repoPath!, versionedPath: file }) + ); + + return Uri.file(file); + } - return Uri.file(file); + return GitUri.toRevisionUri(sha, fileName, repoPath!); } getVersionedFileText(repoPath: string, fileName: string, sha: string) { diff --git a/src/trackers/documentTracker.ts b/src/trackers/documentTracker.ts index 212bf54..05eeeb4 100644 --- a/src/trackers/documentTracker.ts +++ b/src/trackers/documentTracker.ts @@ -238,7 +238,7 @@ export class DocumentTracker implements Disposable { private async _add(documentOrId: TextDocument | Uri): Promise> { if (documentOrId instanceof GitUri) { try { - documentOrId = await workspace.openTextDocument(documentOrId.fileUri({ useVersionedPath: true })); + documentOrId = await workspace.openTextDocument(documentOrId.documentUri({ useVersionedPath: true })); } catch (ex) { const msg = ex.toString(); @@ -271,7 +271,7 @@ export class DocumentTracker implements Disposable { private async _get(documentOrId: string | TextDocument | Uri) { if (documentOrId instanceof GitUri) { - documentOrId = GitUri.toKey(documentOrId.fileUri({ useVersionedPath: true })); + documentOrId = GitUri.toKey(documentOrId.documentUri({ useVersionedPath: true })); } else if (typeof documentOrId === 'string' || documentOrId instanceof Uri) { documentOrId = GitUri.toKey(documentOrId); @@ -366,7 +366,7 @@ class EmptyTextDocument implements TextDocument { constructor( public readonly gitUri: GitUri ) { - this.uri = gitUri.fileUri({ useVersionedPath: true }); + this.uri = gitUri.documentUri({ useVersionedPath: true }); this.eol = EndOfLine.LF; this.fileName = this.uri.fsPath;