Adds gitlens.diffWithPrevious command to the explore context menu

Adds output channel logging, controlled by the `gitlens.advanced.output.level` setting
Removes all debug logging, unless the `gitlens.advanced.output.debug` settings it on
This commit is contained in:
Eric Amodio
2016-11-08 03:38:33 -05:00
parent 409be335f9
commit 562afeaaad
17 changed files with 330 additions and 191 deletions

View File

@@ -1,7 +1,7 @@
'use strict';
import { Iterables } from './system';
import { commands, DecorationOptions, Disposable, ExtensionContext, OverviewRulerLane, Range, TextDocument, TextEditor, TextEditorDecorationType, TextEditorSelectionChangeEvent, Uri, window, workspace } from 'vscode';
import { BuiltInCommands} from './constants';
import { BuiltInCommands } from './constants';
import { BlameAnnotationStyle, IBlameConfig } from './configuration';
import GitProvider, { IGitBlame, IGitCommit } from './gitProvider';
import * as moment from 'moment';

View File

@@ -5,6 +5,7 @@ import { EditorCommand } from './commands';
import { BuiltInCommands, Commands } from '../constants';
import BlameAnnotationController from '../blameAnnotationController';
import GitProvider from '../gitProvider';
import { Logger } from '../logger';
import * as path from 'path';
export default class DiffWithPreviousCommand extends EditorCommand {
@@ -22,7 +23,7 @@ export default class DiffWithPreviousCommand extends EditorCommand {
return Promise.all([this.git.getVersionedFile(shaUri.fsPath, repoPath, sha), this.git.getVersionedFile(compareWithUri.fsPath, repoPath, compareWithSha)])
.then(values => commands.executeCommand(BuiltInCommands.Diff, Uri.file(values[1]), Uri.file(values[0]), `${path.basename(compareWithUri.fsPath)} (${compareWithSha}) ↔ ${path.basename(shaUri.fsPath)} (${sha})`))
.then(() => commands.executeCommand(BuiltInCommands.RevealLine, { lineNumber: line, at: 'center' }))
.catch(ex => console.error('[GitLens.DiffWithPreviousCommand]', 'getVersionedFile', ex));
.catch(ex => Logger.error('[GitLens.DiffWithPreviousCommand]', 'getVersionedFile', ex));
}
if (!(uri instanceof Uri)) {
@@ -46,13 +47,13 @@ export default class DiffWithPreviousCommand extends EditorCommand {
return commands.executeCommand(Commands.DiffWithPrevious, commit.previousUri, commit.repoPath, commit.previousSha, commit.previousUri, prevCommit.sha, prevCommit.uri, blame.line.originalLine);
}
catch (ex) {
console.error('[GitLens.DiffWithPreviousCommand]', `getBlameForLine(${blame.line.originalLine}, ${commit.previousSha})`, ex);
Logger.error('[GitLens.DiffWithPreviousCommand]', `getBlameForLine(${blame.line.originalLine}, ${commit.previousSha})`, ex);
}
}
return commands.executeCommand(Commands.DiffWithPrevious, commit.uri, commit.repoPath, commit.sha, commit.uri, commit.previousSha, commit.previousUri, line);
}
catch (ex) {
console.error('[GitLens.DiffWithPreviousCommand]', `getBlameForLine(${line})`, ex);
Logger.error('[GitLens.DiffWithPreviousCommand]', `getBlameForLine(${line})`, ex);
}
}
else {
@@ -66,7 +67,7 @@ export default class DiffWithPreviousCommand extends EditorCommand {
return commands.executeCommand(Commands.DiffWithPrevious, commit.uri, commit.repoPath, commit.sha, commit.uri, prevCommit.sha, prevCommit.uri, line);
}
catch (ex) {
console.error('[GitLens.DiffWithPreviousCommand]', `getLogForFile(${uri.fsPath})`, ex);
Logger.error('[GitLens.DiffWithPreviousCommand]', `getLogForFile(${uri.fsPath})`, ex);
}
}
}

View File

@@ -5,6 +5,7 @@ import { EditorCommand } from './commands';
import { BuiltInCommands, Commands } from '../constants';
import BlameAnnotationController from '../blameAnnotationController';
import GitProvider from '../gitProvider';
import { Logger } from '../logger';
import * as path from 'path';
export default class DiffWithWorkingCommand extends EditorCommand {
@@ -18,7 +19,7 @@ export default class DiffWithWorkingCommand extends EditorCommand {
return this.git.getVersionedFile(shaUri.fsPath, repoPath, sha)
.then(compare => commands.executeCommand(BuiltInCommands.Diff, Uri.file(compare), uri, `${path.basename(shaUri.fsPath)} (${sha}) ↔ ${path.basename(uri.fsPath)}`))
.then(() => commands.executeCommand(BuiltInCommands.RevealLine, { lineNumber: line, at: 'center' }))
.catch(ex => console.error('[GitLens.DiffWithWorkingCommand]', 'getVersionedFile', ex));
.catch(ex => Logger.error('[GitLens.DiffWithWorkingCommand]', 'getVersionedFile', ex));
}
if (!(uri instanceof Uri)) {
@@ -39,7 +40,7 @@ export default class DiffWithWorkingCommand extends EditorCommand {
return commands.executeCommand(Commands.DiffWithWorking, commit.uri, commit.repoPath, commit.sha, commit.uri, line);
}
catch (ex) {
console.error('[GitLens.DiffWithWorkingCommand]', `getBlameForLine(${line})`, ex);
Logger.error('[GitLens.DiffWithWorkingCommand]', `getBlameForLine(${line})`, ex);
}
}
else {
@@ -51,7 +52,7 @@ export default class DiffWithWorkingCommand extends EditorCommand {
return commands.executeCommand(Commands.DiffWithWorking, commit.uri, commit.repoPath, commit.sha, commit.uri, line);
}
catch (ex) {
console.error('[GitLens.DiffWithPreviousCommand]', `getLogForFile(${uri.fsPath})`, ex);
Logger.error('[GitLens.DiffWithPreviousCommand]', `getLogForFile(${uri.fsPath})`, ex);
}
}
}

View File

@@ -4,6 +4,7 @@ import BlameAnnotationController from '../blameAnnotationController';
import { EditorCommand } from './commands';
import { Commands } from '../constants';
import GitProvider from '../gitProvider';
import { Logger } from '../logger';
export default class ShowBlameCommand extends EditorCommand {
constructor(private git: GitProvider, private annotationController: BlameAnnotationController) {
@@ -25,7 +26,7 @@ export default class ShowBlameCommand extends EditorCommand {
this.annotationController.showBlameAnnotation(editor, blame && blame.commit.sha);
}
catch (ex) {
console.error('[GitLens.ShowBlameCommand]', `getBlameForLine(${editor.selection.active.line})`, ex);
Logger.error('[GitLens.ShowBlameCommand]', `getBlameForLine(${editor.selection.active.line})`, ex);
}
}
}

View File

@@ -3,6 +3,7 @@ import { commands, Position, Range, TextEditor, TextEditorEdit, Uri } from 'vsco
import { EditorCommand } from './commands';
import { BuiltInCommands, Commands } from '../constants';
import GitProvider from '../gitProvider';
import { Logger } from '../logger';
export default class ShowBlameHistoryCommand extends EditorCommand {
constructor(private git: GitProvider) {
@@ -24,7 +25,7 @@ export default class ShowBlameHistoryCommand extends EditorCommand {
return commands.executeCommand(BuiltInCommands.ShowReferences, uri, position, locations);
}
catch (ex) {
console.error('[GitLens.ShowBlameHistoryCommand]', 'getBlameLocations', ex);
Logger.error('[GitLens.ShowBlameHistoryCommand]', 'getBlameLocations', ex);
}
}
}

View File

@@ -1,8 +1,9 @@
'use strict';
import { commands, Position, Range, TextEditor, TextEditorEdit, Uri } from 'vscode';
import { EditorCommand} from './commands';
import { EditorCommand } from './commands';
import { BuiltInCommands, Commands } from '../constants';
import GitProvider from '../gitProvider';
import { Logger } from '../logger';
export default class ShowHistoryCommand extends EditorCommand {
constructor(private git: GitProvider) {
@@ -23,7 +24,7 @@ export default class ShowHistoryCommand extends EditorCommand {
return commands.executeCommand(BuiltInCommands.ShowReferences, uri, position, locations);
}
catch (ex) {
console.error('[GitLens.ShowHistoryCommand]', 'getLogLocations', ex);
Logger.error('[GitLens.ShowHistoryCommand]', 'getLogLocations', ex);
}
}
}

View File

@@ -4,8 +4,9 @@ import BlameAnnotationController from '../blameAnnotationController';
import { EditorCommand } from './commands';
import { Commands } from '../constants';
import GitProvider from '../gitProvider';
import { Logger } from '../logger';
export default class ToggleBlameCommand extends EditorCommand {
export default class ToggleBlameCommand extends EditorCommand {
constructor(private git: GitProvider, private annotationController: BlameAnnotationController) {
super(Commands.ToggleBlame);
}
@@ -25,7 +26,7 @@ export default class ToggleBlameCommand extends EditorCommand {
this.annotationController.toggleBlameAnnotation(editor, blame && blame.commit.sha);
}
catch (ex) {
console.error('[GitLens.ToggleBlameCommand]', `getBlameForLine(${editor.selection.active.line})`, ex);
Logger.error('[GitLens.ToggleBlameCommand]', `getBlameForLine(${editor.selection.active.line})`, ex);
}
}
}

View File

@@ -1,5 +1,5 @@
'use strict';
import {Commands} from './constants';
import { Commands } from './constants';
export type BlameAnnotationStyle = 'compact' | 'expanded';
export const BlameAnnotationStyle = {
@@ -66,9 +66,20 @@ export interface IStatusBarConfig {
command: StatusBarCommand;
}
export type OutputLevel = 'silent' | 'errors' | 'verbose';
export const OutputLevel = {
Silent: 'silent' as OutputLevel,
Errors: 'errors' as OutputLevel,
Verbose: 'verbose' as OutputLevel
};
export interface IAdvancedConfig {
caching: {
enabled: boolean
enabled: boolean;
};
output: {
debug: boolean;
level: OutputLevel;
};
}

View File

@@ -14,18 +14,19 @@ import ShowBlameHistoryCommand from './commands/showBlameHistory';
import ShowHistoryCommand from './commands/showHistory';
import ToggleBlameCommand from './commands/toggleBlame';
import ToggleCodeLensCommand from './commands/toggleCodeLens';
import { Logger } from './logger';
// this method is called when your extension is activated
export function activate(context: ExtensionContext) {
// Workspace not using a folder. No access to git repo.
if (!workspace.rootPath) {
console.warn('GitLens inactive: no rootPath');
Logger.warn('GitLens inactive: no rootPath');
return;
}
const rootPath = workspace.rootPath.replace(/\\/g, '/');
console.log(`GitLens active: ${rootPath}`);
Logger.log(`GitLens active: ${rootPath}`);
Git.repoPath(rootPath).then(repoPath => {
context.workspaceState.update(WorkspaceState.RepoPath, repoPath);
@@ -52,7 +53,7 @@ export function activate(context: ExtensionContext) {
context.subscriptions.push(new ShowBlameHistoryCommand(git));
context.subscriptions.push(new ShowHistoryCommand(git));
context.subscriptions.push(new ToggleCodeLensCommand(git));
}).catch(reason => console.warn('[GitLens]', reason));
}).catch(reason => Logger.warn(reason));
}
// this method is called when your extension is deactivated

View File

@@ -3,6 +3,7 @@ import * as fs from 'fs';
import * as path from 'path';
import * as tmp from 'tmp';
import { spawnPromise } from 'spawn-rx';
import { Logger } from '../logger';
export * from './gitEnrichment';
export * from './enrichers/blameParserEnricher';
@@ -10,18 +11,18 @@ export * from './enrichers/logParserEnricher';
const UncommittedRegex = /^[0]+$/;
async function gitCommand(cwd: string, ...args: any[]) {
async function gitCommand(cwd: string, ...args: any[]) {
try {
const s = await spawnPromise('git', args, { cwd: cwd });
console.log('[GitLens]', 'git', ...args, cwd);
Logger.log('git', ...args, cwd);
return s;
}
catch (ex) {
const msg = ex && ex.toString();
if (msg && (msg.includes('is outside repository') || msg.includes('no such path'))) {
console.warn('[GitLens]', 'git', ...args, cwd, msg && msg.replace(/\r?\n|\r/g, ' '));
Logger.warn('git', ...args, cwd, msg && msg.replace(/\r?\n|\r/g, ' '));
} else {
console.error('[GitLens]', 'git', ...args, cwd, msg && msg.replace(/\r?\n|\r/g, ' '));
Logger.error('git', ...args, cwd, msg && msg.replace(/\r?\n|\r/g, ' '));
}
throw ex;
}
@@ -41,7 +42,7 @@ export default class Git {
static splitPath(fileName: string, repoPath?: string): [string, string] {
// if (!path.isAbsolute(fileName)) {
// console.error('[GitLens]', `Git.splitPath(${fileName}) is not an absolute path!`);
// Logger.error(`Git.splitPath(${fileName}) is not an absolute path!`);
// debugger;
// }
if (repoPath) {
@@ -89,7 +90,7 @@ export default class Git {
return;
}
//console.log(`getVersionedFile(${fileName}, ${sha}); destination=${destination}`);
//Logger.log(`getVersionedFile(${fileName}, ${sha}); destination=${destination}`);
fs.appendFile(destination, data, err => {
if (err) {
reject(err);

View File

@@ -1,7 +1,8 @@
'use strict';
import { EventEmitter, ExtensionContext, OverviewRulerLane, Range, TextEditor, TextEditorDecorationType, TextDocumentContentProvider, Uri, window } from 'vscode';
import { DocumentSchemes } from './constants';
import GitProvider, {IGitBlameUriData} from './gitProvider';
import GitProvider, { IGitBlameUriData } from './gitProvider';
import { Logger } from './logger';
import * as moment from 'moment';
export default class GitBlameContentProvider implements TextDocumentContentProvider {
@@ -29,7 +30,7 @@ export default class GitBlameContentProvider implements TextDocumentContentProvi
});
//this._subscriptions = Disposable.from(
// window.onDidChangeActiveTextEditor(e => e ? console.log(e.document.uri) : console.log('active missing')),
// window.onDidChangeActiveTextEditor(e => e ? Logger.log(e.document.uri) : Logger.log('active missing')),
//);
}
@@ -63,7 +64,7 @@ export default class GitBlameContentProvider implements TextDocumentContentProvi
return text;
})
.catch(ex => console.error('[GitLens.GitBlameContentProvider]', 'getVersionedFileText', ex));
.catch(ex => Logger.error('[GitLens.GitBlameContentProvider]', 'getVersionedFileText', ex));
// return this.git.getVersionedFile(data.fileName, data.sha).then(dst => {
// let uri = Uri.parse(`file:${dst}`)

View File

@@ -1,7 +1,8 @@
'use strict';
import {ExtensionContext, TextDocumentContentProvider, Uri} from 'vscode';
import {DocumentSchemes} from './constants';
import { ExtensionContext, TextDocumentContentProvider, Uri } from 'vscode';
import { DocumentSchemes } from './constants';
import GitProvider from './gitProvider';
import { Logger } from './logger';
export default class GitContentProvider implements TextDocumentContentProvider {
static scheme = DocumentSchemes.Git;
@@ -12,6 +13,6 @@ export default class GitContentProvider implements TextDocumentContentProvider {
const data = GitProvider.fromGitUri(uri);
return this.git.getVersionedFileText(data.originalFileName || data.fileName, data.repoPath, data.sha)
.then(text => data.decoration ? `${data.decoration}\n${text}` : text)
.catch(ex => console.error('[GitLens.GitContentProvider]', 'getVersionedFileText', ex));
.catch(ex => Logger.error('[GitLens.GitContentProvider]', 'getVersionedFileText', ex));
}
}

View File

@@ -5,6 +5,7 @@ import { DocumentSchemes, WorkspaceState } from './constants';
import { CodeLensVisibility, IConfig } from './configuration';
import GitCodeLensProvider from './gitCodeLensProvider';
import Git, { GitBlameParserEnricher, GitBlameFormat, GitCommit, GitLogParserEnricher, IGitAuthor, IGitBlame, IGitBlameCommitLines, IGitBlameLine, IGitBlameLines, IGitCommit, IGitLog } from './git/git';
import { Logger } from './logger';
import * as fs from 'fs';
import * as ignore from 'ignore';
import * as moment from 'moment';
@@ -149,7 +150,7 @@ export default class GitProvider extends Disposable {
}
if (this._cache.delete(cacheKey)) {
console.log('[GitLens]', `Clear cache entry: cacheKey=${cacheKey}, reason=${RemoveCacheReason[reason]}`);
Logger.log(`Clear cache entry for '${cacheKey}', reason=${RemoveCacheReason[reason]}`);
// if (reason === RemoveCacheReason.DocumentSaved) {
// // TODO: Killing the code lens provider is too drastic -- makes the editor jump around, need to figure out how to trigger a refresh
@@ -163,6 +164,7 @@ export default class GitProvider extends Disposable {
}
async getBlameForFile(fileName: string): Promise<IGitBlame | null> {
Logger.log(`getBlameForFile('${fileName}')`);
fileName = Git.normalizePath(fileName);
const cacheKey = this._getCacheEntryKey(fileName);
@@ -178,7 +180,7 @@ export default class GitProvider extends Disposable {
const ignore = await this._gitignore;
let blame: Promise<IGitBlame>;
if (ignore && !ignore.filter([fileName]).length) {
console.log('[GitLens]', `Skipping blame; ${fileName} is gitignored`);
Logger.log(`Skipping blame; '${fileName}' is gitignored`);
blame = GitProvider.EmptyPromise;
}
else {
@@ -188,7 +190,7 @@ export default class GitProvider extends Disposable {
// Trap and cache expected blame errors
if (this.UseCaching) {
const msg = ex && ex.toString();
console.log('[GitLens]', `Replace blame cache: cacheKey=${cacheKey}`);
Logger.log(`Replace blame cache with empty promise for '${cacheKey}'`);
entry.blame = <ICachedBlame>{
//date: new Date(),
@@ -204,7 +206,7 @@ export default class GitProvider extends Disposable {
}
if (this.UseCaching) {
console.log('[GitLens]', `Add blame cache: cacheKey=${cacheKey}`);
Logger.log(`Add ${(blame === GitProvider.EmptyPromise ? 'empty promise to ' : '')}blame cache for '${cacheKey}'`);
entry.blame = <ICachedBlame>{
//date: new Date(),
@@ -218,6 +220,8 @@ export default class GitProvider extends Disposable {
}
async getBlameForLine(fileName: string, line: number, sha?: string, repoPath?: string): Promise<IGitBlameLine | null> {
Logger.log(`getBlameForLine('${fileName}', ${line}, ${sha}, ${repoPath})`);
if (this.UseCaching && !sha) {
const blame = await this.getBlameForFile(fileName);
const blameLine = blame && blame.lines[line];
@@ -254,6 +258,8 @@ export default class GitProvider extends Disposable {
}
async getBlameForRange(fileName: string, range: Range): Promise<IGitBlameLines | null> {
Logger.log(`getBlameForRange('${fileName}', ${range})`);
const blame = await this.getBlameForFile(fileName);
if (!blame) return null;
@@ -302,6 +308,8 @@ export default class GitProvider extends Disposable {
}
async getBlameForShaRange(fileName: string, sha: string, range: Range): Promise<IGitBlameCommitLines | null> {
Logger.log(`getBlameForShaRange('${fileName}', ${sha}, ${range})`);
const blame = await this.getBlameForFile(fileName);
if (!blame) return null;
@@ -317,6 +325,8 @@ export default class GitProvider extends Disposable {
}
async getBlameLocations(fileName: string, range: Range): Promise<Location[] | null> {
Logger.log(`getBlameForShaRange('${fileName}', ${range})`);
const blame = await this.getBlameForRange(fileName, range);
if (!blame) return null;
@@ -337,6 +347,7 @@ export default class GitProvider extends Disposable {
}
async getLogForFile(fileName: string) {
Logger.log(`getLogForFile('${fileName}')`);
fileName = Git.normalizePath(fileName);
const cacheKey = this._getCacheEntryKey(fileName);
@@ -352,7 +363,7 @@ export default class GitProvider extends Disposable {
const ignore = await this._gitignore;
let log: Promise<IGitLog>;
if (ignore && !ignore.filter([fileName]).length) {
console.log('[GitLens]', `Skipping log; ${fileName} is gitignored`);
Logger.log(`Skipping log; '${fileName}' is gitignored`);
log = GitProvider.EmptyPromise;
}
else {
@@ -362,7 +373,7 @@ export default class GitProvider extends Disposable {
// Trap and cache expected blame errors
if (this.UseCaching) {
const msg = ex && ex.toString();
console.log('[GitLens]', `Replace log cache: cacheKey=${cacheKey}`);
Logger.log(`Replace log cache with empty promise for '${cacheKey}'`);
entry.log = <ICachedLog>{
//date: new Date(),
@@ -378,7 +389,7 @@ export default class GitProvider extends Disposable {
}
if (this.UseCaching) {
console.log('[GitLens]', `Add log cache: cacheKey=${cacheKey}`);
Logger.log(`Add ${(log === GitProvider.EmptyPromise ? 'empty promise to ' : '')}log cache for '${cacheKey}'`);
entry.log = <ICachedLog>{
//date: new Date(),
@@ -392,6 +403,8 @@ export default class GitProvider extends Disposable {
}
async getLogLocations(fileName: string): Promise<Location[] | null> {
Logger.log(`getLogLocations('${fileName}')`);
const log = await this.getLogForFile(fileName);
if (!log) return null;
@@ -412,14 +425,18 @@ export default class GitProvider extends Disposable {
}
getVersionedFile(fileName: string, repoPath: string, sha: string) {
Logger.log(`getVersionedFile('${fileName}', ${repoPath}, ${sha})`);
return Git.getVersionedFile(fileName, repoPath, sha);
}
getVersionedFileText(fileName: string, repoPath: string, sha: string) {
Logger.log(`getVersionedFileText('${fileName}', ${repoPath}, ${sha})`);
return Git.getVersionedFileText(fileName, repoPath, sha);
}
toggleCodeLens(editor: TextEditor) {
Logger.log(`toggleCodeLens(${editor})`);
if (this._config.codeLens.visibility !== CodeLensVisibility.OnDemand ||
(!this._config.codeLens.recentChange.enabled && !this._config.codeLens.authors.enabled)) return;

57
src/logger.ts Normal file
View File

@@ -0,0 +1,57 @@
'use strict';
import { Objects } from './system';
import { OutputChannel, window, workspace } from 'vscode';
import { IAdvancedConfig, OutputLevel } from './configuration';
let config: IAdvancedConfig;
let output: OutputChannel;
workspace.onDidChangeConfiguration(onConfigurationChange);
onConfigurationChange();
function onConfigurationChange() {
const cfg = workspace.getConfiguration('gitlens').get<IAdvancedConfig>('advanced');
if (!Objects.areEquivalent(cfg.output, config && config.output)) {
if (cfg.output.level === OutputLevel.Silent) {
output && output.dispose();
}
else if (!output) {
output = window.createOutputChannel('GitLens');
}
}
config = cfg;
}
export class Logger {
static log(message?: any, ...params: any[]): void {
if (config.output.debug) {
console.log('[GitLens]', message, ...params);
}
if (config.output.level === OutputLevel.Verbose) {
output.appendLine([message, ...params].join(' '));
}
}
static error(message?: any, ...params: any[]): void {
if (config.output.debug) {
console.error('[GitLens]', message, ...params);
}
if (config.output.level !== OutputLevel.Silent) {
output.appendLine([message, ...params].join(' '));
}
}
static warn(message?: any, ...params: any[]): void {
if (config.output.debug) {
console.warn('[GitLens]', message, ...params);
}
if (config.output.level !== OutputLevel.Silent) {
output.appendLine([message, ...params].join(' '));
}
}
}