Merge from vscode 071a5cf16fc999727acc31c790d78f750fa4b166 (#5261)

This commit is contained in:
Anthony Dresser
2019-04-30 07:54:56 -07:00
committed by GitHub
parent 02916aeffa
commit aacc0eca67
24 changed files with 564 additions and 238 deletions

View File

@@ -322,15 +322,17 @@ export class CommentService extends Disposable implements ICommentService {
}
}
let commentControlResult: Promise<ICommentInfo>[] = [];
let commentControlResult: Promise<ICommentInfo | null>[] = [];
this._commentControls.forEach(control => {
commentControlResult.push(control.getDocumentComments(resource, CancellationToken.None));
commentControlResult.push(control.getDocumentComments(resource, CancellationToken.None)
.catch(e => {
console.log(e);
return null;
}));
});
let ret = [...await Promise.all(result), ...await Promise.all(commentControlResult)];
return ret;
return Promise.all([...result, ...commentControlResult]);
}
async getCommentingRanges(resource: URI): Promise<IRange[]> {

View File

@@ -212,6 +212,7 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget
} else {
const deleteCommand = (this._commentThread as modes.CommentThread2).deleteCommand;
if (deleteCommand) {
this.commentService.setActiveCommentThread(this._commentThread);
return this.commandService.executeCommand(deleteCommand.id, ...(deleteCommand.arguments || []));
}
}
@@ -239,7 +240,7 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget
}
}
async update(commentThread: modes.CommentThread | modes.CommentThread2) {
async update(commentThread: modes.CommentThread | modes.CommentThread2, replaceTemplate: boolean = false) {
const oldCommentsLen = this._commentElements.length;
const newCommentsLen = commentThread.comments ? commentThread.comments.length : 0;
@@ -288,12 +289,20 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget
this._commentThread = commentThread;
this._commentElements = newCommentNodeList;
this.createThreadLabel();
this.createThreadLabel(replaceTemplate);
if (replaceTemplate) {
this.createTextModelListener();
}
if (this._formActions && this._commentEditor.hasModel()) {
dom.clearNode(this._formActions);
const model = this._commentEditor.getModel();
this.createCommentWidgetActions2(this._formActions, model);
if (replaceTemplate) {
this.createCommentWidgetActionsListener(this._formActions, model);
}
}
// Move comment glyph widget and show position if the line has changed.
@@ -348,7 +357,7 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget
this._commentEditor.layout({ height: 5 * 18, width: widthInPixel - 54 /* margin 20px * 10 + scrollbar 14px*/ });
}
display(lineNumber: number) {
display(lineNumber: number, fromTemplate: boolean = false) {
this._commentGlyph = new CommentGlyphWidget(this.editor, lineNumber);
this._disposables.push(this.editor.onMouseDown(e => this.onEditorMouseDown(e)));
@@ -386,58 +395,8 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget
this._commentEditor.setModel(model);
this._disposables.push(this._commentEditor);
this._disposables.push(this._commentEditor.getModel()!.onDidChangeContent(() => this.setCommentEditorDecorations()));
if ((this._commentThread as modes.CommentThread2).commentThreadHandle !== undefined) {
this._disposables.push(this._commentEditor.onDidFocusEditorWidget(() => {
let commentThread = this._commentThread as modes.CommentThread2;
commentThread.input = {
uri: this._commentEditor.getModel()!.uri,
value: this._commentEditor.getValue()
};
this.commentService.setActiveCommentThread(this._commentThread);
}));
this._disposables.push(this._commentEditor.getModel()!.onDidChangeContent(() => {
let modelContent = this._commentEditor.getValue();
let thread = (this._commentThread as modes.CommentThread2);
if (thread.input && thread.input.uri === this._commentEditor.getModel()!.uri && thread.input.value !== modelContent) {
let newInput: modes.CommentInput = thread.input;
newInput.value = modelContent;
thread.input = newInput;
}
}));
this._disposables.push((this._commentThread as modes.CommentThread2).onDidChangeInput(input => {
let thread = (this._commentThread as modes.CommentThread2);
if (thread.input && thread.input.uri !== this._commentEditor.getModel()!.uri) {
return;
}
if (!input) {
return;
}
if (this._commentEditor.getValue() !== input.value) {
this._commentEditor.setValue(input.value);
if (input.value === '') {
this._pendingComment = '';
if (dom.hasClass(this._commentForm, 'expand')) {
dom.removeClass(this._commentForm, 'expand');
}
this._commentEditor.getDomNode()!.style.outline = '';
this._error.textContent = '';
dom.addClass(this._error, 'hidden');
}
}
}));
this._disposables.push((this._commentThread as modes.CommentThread2).onDidChangeComments(async _ => {
await this.update(this._commentThread);
}));
this._disposables.push((this._commentThread as modes.CommentThread2).onDidChangeLabel(_ => {
this.createThreadLabel();
}));
if ((this._commentThread as modes.CommentThread2).commentThreadHandle !== undefined && !fromTemplate) {
this.createTextModelListener();
}
this.setCommentEditorDecorations();
@@ -456,50 +415,9 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget
this._formActions = dom.append(this._commentForm, dom.$('.form-actions'));
if ((this._commentThread as modes.CommentThread2).commentThreadHandle !== undefined) {
this.createCommentWidgetActions2(this._formActions, model);
this._disposables.push((this._commentThread as modes.CommentThread2).onDidChangeAcceptInputCommand(_ => {
if (this._formActions) {
dom.clearNode(this._formActions);
this.createCommentWidgetActions2(this._formActions, model);
}
}));
this._disposables.push((this._commentThread as modes.CommentThread2).onDidChangeAdditionalCommands(_ => {
if (this._formActions) {
dom.clearNode(this._formActions);
this.createCommentWidgetActions2(this._formActions, model);
}
}));
this._disposables.push((this._commentThread as modes.CommentThread2).onDidChangeRange(range => {
// Move comment glyph widget and show position if the line has changed.
const lineNumber = this._commentThread.range.startLineNumber;
let shouldMoveWidget = false;
if (this._commentGlyph) {
if (this._commentGlyph.getPosition().position!.lineNumber !== lineNumber) {
shouldMoveWidget = true;
this._commentGlyph.setLineNumber(lineNumber);
}
}
if (shouldMoveWidget && this._isExpanded) {
this.show({ lineNumber, column: 1 }, 2);
}
}));
this._disposables.push((this._commentThread as modes.CommentThread2).onDidChangeCollasibleState(state => {
if (state === modes.CommentThreadCollapsibleState.Expanded && !this._isExpanded) {
const lineNumber = this._commentThread.range.startLineNumber;
this.show({ lineNumber, column: 1 }, 2);
return;
}
if (state === modes.CommentThreadCollapsibleState.Collapsed && this._isExpanded) {
this.hide();
return;
}
}));
if (!fromTemplate) {
this.createCommentWidgetActionsListener(this._formActions, model);
}
} else {
this.createCommentWidgetActions(this._formActions, model);
}
@@ -526,6 +444,106 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget
}
}
private createTextModelListener() {
this._disposables.push(this._commentEditor.onDidFocusEditorWidget(() => {
let commentThread = this._commentThread as modes.CommentThread2;
commentThread.input = {
uri: this._commentEditor.getModel()!.uri,
value: this._commentEditor.getValue()
};
this.commentService.setActiveCommentThread(this._commentThread);
}));
this._disposables.push(this._commentEditor.getModel()!.onDidChangeContent(() => {
let modelContent = this._commentEditor.getValue();
let thread = (this._commentThread as modes.CommentThread2);
if (thread.input && thread.input.uri === this._commentEditor.getModel()!.uri && thread.input.value !== modelContent) {
let newInput: modes.CommentInput = thread.input;
newInput.value = modelContent;
thread.input = newInput;
}
}));
this._disposables.push((this._commentThread as modes.CommentThread2).onDidChangeInput(input => {
let thread = (this._commentThread as modes.CommentThread2);
if (thread.input && thread.input.uri !== this._commentEditor.getModel()!.uri) {
return;
}
if (!input) {
return;
}
if (this._commentEditor.getValue() !== input.value) {
this._commentEditor.setValue(input.value);
if (input.value === '') {
this._pendingComment = '';
if (dom.hasClass(this._commentForm, 'expand')) {
dom.removeClass(this._commentForm, 'expand');
}
this._commentEditor.getDomNode()!.style.outline = '';
this._error.textContent = '';
dom.addClass(this._error, 'hidden');
}
}
}));
this._disposables.push((this._commentThread as modes.CommentThread2).onDidChangeComments(async _ => {
await this.update(this._commentThread);
}));
this._disposables.push((this._commentThread as modes.CommentThread2).onDidChangeLabel(_ => {
this.createThreadLabel();
}));
}
private createCommentWidgetActionsListener(container: HTMLElement, model: ITextModel) {
this._disposables.push((this._commentThread as modes.CommentThread2).onDidChangeAcceptInputCommand(_ => {
if (container) {
dom.clearNode(container);
this.createCommentWidgetActions2(container, model);
}
}));
this._disposables.push((this._commentThread as modes.CommentThread2).onDidChangeAdditionalCommands(_ => {
if (container) {
dom.clearNode(container);
this.createCommentWidgetActions2(container, model);
}
}));
this._disposables.push((this._commentThread as modes.CommentThread2).onDidChangeRange(range => {
// Move comment glyph widget and show position if the line has changed.
const lineNumber = this._commentThread.range.startLineNumber;
let shouldMoveWidget = false;
if (this._commentGlyph) {
if (this._commentGlyph.getPosition().position!.lineNumber !== lineNumber) {
shouldMoveWidget = true;
this._commentGlyph.setLineNumber(lineNumber);
}
}
if (shouldMoveWidget && this._isExpanded) {
this.show({ lineNumber, column: 1 }, 2);
}
}));
this._disposables.push((this._commentThread as modes.CommentThread2).onDidChangeCollasibleState(state => {
if (state === modes.CommentThreadCollapsibleState.Expanded && !this._isExpanded) {
const lineNumber = this._commentThread.range.startLineNumber;
this.show({ lineNumber, column: 1 }, 2);
return;
}
if (state === modes.CommentThreadCollapsibleState.Collapsed && this._isExpanded) {
this.hide();
return;
}
}));
}
private handleError(e: Error) {
this._error.textContent = e.message;
this._commentEditor.getDomNode()!.style.outline = `1px solid ${this.themeService.getTheme().getColor(inputValidationErrorBorder)}`;
@@ -798,13 +816,14 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget
}
}
private createThreadLabel() {
private createThreadLabel(replaceTemplate: boolean = false) {
let label: string | undefined;
if ((this._commentThread as modes.CommentThread2).commentThreadHandle !== undefined) {
label = (this._commentThread as modes.CommentThread2).label;
}
if (label === undefined) {
if (label === undefined && !replaceTemplate) {
// if it's for replacing the comment thread template, the comment thread widget title can be undefined as extensions may set it later
if (this._commentThread.comments && this._commentThread.comments.length) {
const participantsList = this._commentThread.comments.filter(arrays.uniqueFilter(comment => comment.userName)).map(comment => `@${comment.userName}`).join(', ');
label = nls.localize('commentThreadParticipants', "Participants: {0}", participantsList);
@@ -813,8 +832,11 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget
}
}
this._headingLabel.innerHTML = strings.escape(label);
this._headingLabel.setAttribute('aria-label', label);
if (label) {
this._headingLabel.innerHTML = strings.escape(label);
this._headingLabel.setAttribute('aria-label', label);
}
}
private expandReplyArea() {

View File

@@ -30,7 +30,7 @@ import { CancelablePromise, createCancelablePromise, Delayer } from 'vs/base/com
import { overviewRulerCommentingRangeForeground } from 'vs/workbench/contrib/comments/browser/commentGlyphWidget';
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
import { STATUS_BAR_ITEM_HOVER_BACKGROUND, STATUS_BAR_ITEM_ACTIVE_BACKGROUND } from 'vs/workbench/common/theme';
import { ICommandService, CommandsRegistry } from 'vs/platform/commands/common/commands';
import { CommandsRegistry } from 'vs/platform/commands/common/commands';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { ctxCommentEditorFocused, SimpleCommentEditor } from 'vs/workbench/contrib/comments/browser/simpleCommentEditor';
import { onUnexpectedError } from 'vs/base/common/errors';
@@ -64,7 +64,7 @@ class CommentingRangeDecoration {
return this._decorationId;
}
constructor(private _editor: ICodeEditor, private _ownerId: string, private _extensionId: string | undefined, private _label: string | undefined, private _range: IRange, private _reply: modes.Command | undefined, commentingOptions: ModelDecorationOptions, private commentingRangesInfo?: modes.CommentingRanges) {
constructor(private _editor: ICodeEditor, private _ownerId: string, private _extensionId: string | undefined, private _label: string | undefined, private _range: IRange, private _reply: modes.Command | undefined, commentingOptions: ModelDecorationOptions, private _template: modes.CommentThreadTemplate | undefined, private commentingRangesInfo?: modes.CommentingRanges) {
const startLineNumber = _range.startLineNumber;
const endLineNumber = _range.endLineNumber;
let commentingRangeDecorations = [{
@@ -81,13 +81,14 @@ class CommentingRangeDecoration {
}
}
public getCommentAction(): { replyCommand: modes.Command | undefined, ownerId: string, extensionId: string | undefined, label: string | undefined, commentingRangesInfo: modes.CommentingRanges | undefined } {
public getCommentAction(): { replyCommand: modes.Command | undefined, ownerId: string, extensionId: string | undefined, label: string | undefined, commentingRangesInfo: modes.CommentingRanges | undefined, template: modes.CommentThreadTemplate | undefined } {
return {
extensionId: this._extensionId,
label: this._label,
replyCommand: this._reply,
ownerId: this._ownerId,
commentingRangesInfo: this.commentingRangesInfo
commentingRangesInfo: this.commentingRangesInfo,
template: this._template
};
}
@@ -124,11 +125,11 @@ class CommentingRangeDecorator {
for (const info of commentInfos) {
if (Array.isArray(info.commentingRanges)) {
info.commentingRanges.forEach(range => {
commentingRangeDecorations.push(new CommentingRangeDecoration(editor, info.owner, info.extensionId, info.label, range, info.reply, this.decorationOptions));
commentingRangeDecorations.push(new CommentingRangeDecoration(editor, info.owner, info.extensionId, info.label, range, info.reply, this.decorationOptions, info.template));
});
} else {
(info.commentingRanges ? info.commentingRanges.ranges : []).forEach(range => {
commentingRangeDecorations.push(new CommentingRangeDecoration(editor, info.owner, info.extensionId, info.label, range, (info.commentingRanges as modes.CommentingRanges).newCommentThreadCommand, this.decorationOptions, info.commentingRanges as modes.CommentingRanges));
commentingRangeDecorations.push(new CommentingRangeDecoration(editor, info.owner, info.extensionId, info.label, range, undefined, this.decorationOptions, info.template, info.commentingRanges as modes.CommentingRanges));
});
}
}
@@ -178,7 +179,6 @@ export class ReviewController implements IEditorContribution {
constructor(
editor: ICodeEditor,
@ICommentService private readonly commentService: ICommentService,
@ICommandService private readonly _commandService: ICommandService,
@INotificationService private readonly notificationService: INotificationService,
@IInstantiationService private readonly instantiationService: IInstantiationService,
@ICodeEditorService private readonly codeEditorService: ICodeEditorService,
@@ -441,6 +441,11 @@ export class ReviewController implements IEditorContribution {
}
});
added.forEach(thread => {
let matchedZones = this._commentWidgets.filter(zoneWidget => zoneWidget.owner === e.owner && zoneWidget.commentThread.threadId === thread.threadId);
if (matchedZones.length) {
return;
}
const pendingCommentText = this._pendingCommentCache[e.owner] && this._pendingCommentCache[e.owner][thread.threadId];
this.displayCommentThread(e.owner, thread, pendingCommentText, draftMode);
this._commentInfos.filter(info => info.owner === e.owner)[0].threads.push(thread);
@@ -457,6 +462,30 @@ export class ReviewController implements IEditorContribution {
this._commentWidgets.push(zoneWidget);
}
private addCommentThreadFromTemplate(lineNumber: number, ownerId: string, extensionId: string | undefined, template: modes.CommentThreadTemplate): ReviewZoneWidget {
let templateReviewZoneWidget = this.instantiationService.createInstance(ReviewZoneWidget, this.editor, ownerId, {
commentThreadHandle: -1,
label: template!.label,
acceptInputCommand: template.acceptInputCommand,
additionalCommands: template.additionalCommands,
deleteCommand: template.deleteCommand,
extensionId: extensionId,
threadId: null,
resource: null,
comments: [],
range: {
startLineNumber: lineNumber,
startColumn: 0,
endLineNumber: lineNumber,
endColumn: 0
},
collapsibleState: modes.CommentThreadCollapsibleState.Expanded,
},
'', modes.DraftMode.NotSupported);
return templateReviewZoneWidget;
}
private addComment(lineNumber: number, replyCommand: modes.Command | undefined, ownerId: string, extensionId: string | undefined, draftMode: modes.DraftMode | undefined, pendingComment: string | null) {
if (this._newCommentWidget) {
this.notificationService.warn(`Please submit the comment at line ${this._newCommentWidget.position ? this._newCommentWidget.position.lineNumber : -1} before creating a new one.`);
@@ -612,16 +641,16 @@ export class ReviewController implements IEditorContribution {
const commentInfos = newCommentInfos.filter(info => info.ownerId === pick.id);
if (commentInfos.length) {
const { replyCommand, ownerId, extensionId, commentingRangesInfo } = commentInfos[0];
this.addCommentAtLine2(lineNumber, replyCommand, ownerId, extensionId, commentingRangesInfo);
const { replyCommand, ownerId, extensionId, commentingRangesInfo, template } = commentInfos[0];
this.addCommentAtLine2(lineNumber, replyCommand, ownerId, extensionId, commentingRangesInfo, template);
}
}).then(() => {
this._addInProgress = false;
});
}
} else {
const { replyCommand, ownerId, extensionId, commentingRangesInfo } = newCommentInfos[0]!;
this.addCommentAtLine2(lineNumber, replyCommand, ownerId, extensionId, commentingRangesInfo);
const { replyCommand, ownerId, extensionId, commentingRangesInfo, template } = newCommentInfos[0]!;
this.addCommentAtLine2(lineNumber, replyCommand, ownerId, extensionId, commentingRangesInfo, template);
}
return Promise.resolve();
@@ -640,11 +669,11 @@ export class ReviewController implements IEditorContribution {
return picks;
}
private getContextMenuActions(commentInfos: { replyCommand: modes.Command | undefined, ownerId: string, extensionId: string | undefined, label: string | undefined, commentingRangesInfo: modes.CommentingRanges | undefined }[], lineNumber: number): (IAction | ContextSubMenu)[] {
private getContextMenuActions(commentInfos: { replyCommand: modes.Command | undefined, ownerId: string, extensionId: string | undefined, label: string | undefined, commentingRangesInfo: modes.CommentingRanges | undefined, template: modes.CommentThreadTemplate | undefined }[], lineNumber: number): (IAction | ContextSubMenu)[] {
const actions: (IAction | ContextSubMenu)[] = [];
commentInfos.forEach(commentInfo => {
const { replyCommand, ownerId, extensionId, label, commentingRangesInfo } = commentInfo;
const { replyCommand, ownerId, extensionId, label, commentingRangesInfo, template } = commentInfo;
actions.push(new Action(
'addCommentThread',
@@ -652,7 +681,7 @@ export class ReviewController implements IEditorContribution {
undefined,
true,
() => {
this.addCommentAtLine2(lineNumber, replyCommand, ownerId, extensionId, commentingRangesInfo);
this.addCommentAtLine2(lineNumber, replyCommand, ownerId, extensionId, commentingRangesInfo, template);
return Promise.resolve();
}
));
@@ -660,17 +689,25 @@ export class ReviewController implements IEditorContribution {
return actions;
}
public addCommentAtLine2(lineNumber: number, replyCommand: modes.Command | undefined, ownerId: string, extensionId: string | undefined, commentingRangesInfo: modes.CommentingRanges | undefined) {
public addCommentAtLine2(lineNumber: number, replyCommand: modes.Command | undefined, ownerId: string, extensionId: string | undefined, commentingRangesInfo: modes.CommentingRanges | undefined, template: modes.CommentThreadTemplate | undefined) {
if (commentingRangesInfo) {
let range = new Range(lineNumber, 1, lineNumber, 1);
if (commentingRangesInfo.newCommentThreadCommand) {
if (replyCommand) {
const commandId = replyCommand.id;
const args = replyCommand.arguments || [];
if (commentingRangesInfo.newCommentThreadCallback && template) {
// create comment widget through template
let commentThreadWidget = this.addCommentThreadFromTemplate(lineNumber, ownerId, extensionId, template);
commentThreadWidget.display(lineNumber, true);
this._commandService.executeCommand(commandId, ...args);
this._addInProgress = false;
}
return commentingRangesInfo.newCommentThreadCallback(this.editor.getModel()!.uri, range)
.then(commentThread => {
commentThreadWidget.update(commentThread!, true);
this._commentWidgets.push(commentThreadWidget);
this.processNextThreadToAdd();
})
.catch(e => {
this.notificationService.error(nls.localize('commentThreadAddFailure', "Adding a new comment thread failed: {0}.", e.message));
commentThreadWidget.dispose();
this.processNextThreadToAdd();
});
} else if (commentingRangesInfo.newCommentThreadCallback) {
return commentingRangesInfo.newCommentThreadCallback(this.editor.getModel()!.uri, range)
.then(_ => {

View File

@@ -13,7 +13,7 @@ import { IExtensionManagementServerService, IExtensionTipsService } from 'vs/pla
import { ILabelService } from 'vs/platform/label/common/label';
import { extensionButtonProminentBackground, extensionButtonProminentForeground, DisabledLabelAction, ReloadAction } from 'vs/workbench/contrib/extensions/electron-browser/extensionsActions';
import { IThemeService, ITheme } from 'vs/platform/theme/common/themeService';
import { STATUS_BAR_HOST_NAME_BACKGROUND, STATUS_BAR_HOST_NAME_FOREGROUND } from 'vs/workbench/common/theme';
import { EXTENSION_BADGE_REMOTE_BACKGROUND, EXTENSION_BADGE_REMOTE_FOREGROUND } from 'vs/workbench/common/theme';
import { REMOTE_HOST_SCHEME } from 'vs/platform/remote/common/remoteHosts';
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
import { Emitter, Event } from 'vs/base/common/event';
@@ -323,8 +323,8 @@ class RemoteBadge extends Disposable {
if (!this.element) {
return;
}
const bgColor = this.themeService.getTheme().getColor(STATUS_BAR_HOST_NAME_BACKGROUND);
const fgColor = this.themeService.getTheme().getColor(STATUS_BAR_HOST_NAME_FOREGROUND);
const bgColor = this.themeService.getTheme().getColor(EXTENSION_BADGE_REMOTE_BACKGROUND);
const fgColor = this.themeService.getTheme().getColor(EXTENSION_BADGE_REMOTE_FOREGROUND);
this.element.style.backgroundColor = bgColor ? bgColor.toString() : '';
this.element.style.color = fgColor ? fgColor.toString() : '';
};

View File

@@ -19,7 +19,7 @@ import { ResourceMap } from 'vs/base/common/map';
import { DiffEditorInput } from 'vs/workbench/common/editor/diffEditorInput';
import { ResourceEditorInput } from 'vs/workbench/common/editor/resourceEditorInput';
import { IContextKeyService, IContextKey, RawContextKey } from 'vs/platform/contextkey/common/contextkey';
import { FileOnDiskContentProvider } from 'vs/workbench/contrib/files/common/files';
import { FileOnDiskContentProvider, resourceToFileOnDisk } from 'vs/workbench/contrib/files/common/files';
import { FileEditorInput } from 'vs/workbench/contrib/files/common/editors/fileEditorInput';
import { IModelService } from 'vs/editor/common/services/modelService';
import { SAVE_FILE_COMMAND_ID, REVERT_FILE_COMMAND_ID, SAVE_FILE_AS_COMMAND_ID, SAVE_FILE_AS_LABEL } from 'vs/workbench/contrib/files/browser/fileCommands';
@@ -248,7 +248,7 @@ class ResolveSaveConflictAction extends Action {
return this.editorService.openEditor(
{
leftResource: resource.with({ scheme: CONFLICT_RESOLUTION_SCHEME }),
leftResource: resourceToFileOnDisk(CONFLICT_RESOLUTION_SCHEME, resource),
rightResource: resource,
label: editorLabel,
options: { pinned: true }

View File

@@ -23,8 +23,6 @@ import { createDecorator } from 'vs/platform/instantiation/common/instantiation'
import { IEditorGroup } from 'vs/workbench/services/editor/common/editorGroupsService';
import { ExplorerItem } from 'vs/workbench/contrib/files/common/explorerModel';
import { once } from 'vs/base/common/functional';
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
import { toLocalResource } from 'vs/base/common/resources';
/**
* Explorer viewlet id.
@@ -133,6 +131,14 @@ export const SortOrderConfiguration = {
export type SortOrder = 'default' | 'mixed' | 'filesFirst' | 'type' | 'modified';
export function resourceToFileOnDisk(scheme: string, resource: URI): URI {
return resource.with({ scheme, query: JSON.stringify({ scheme: resource.scheme }) });
}
export function fileOnDiskToResource(resource: URI): URI {
return resource.with({ scheme: JSON.parse(resource.query)['scheme'], query: null });
}
export class FileOnDiskContentProvider implements ITextModelContentProvider {
private fileWatcherDisposable: IDisposable | undefined;
@@ -140,13 +146,12 @@ export class FileOnDiskContentProvider implements ITextModelContentProvider {
@ITextFileService private readonly textFileService: ITextFileService,
@IFileService private readonly fileService: IFileService,
@IModeService private readonly modeService: IModeService,
@IModelService private readonly modelService: IModelService,
@IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService
@IModelService private readonly modelService: IModelService
) {
}
provideTextContent(resource: URI): Promise<ITextModel> {
const savedFileResource = toLocalResource(resource, this.environmentService.configuration.remoteAuthority);
const savedFileResource = fileOnDiskToResource(resource);
// Make sure our file from disk is resolved up to date
return this.resolveEditorModel(resource).then(codeEditorModel => {
@@ -174,7 +179,7 @@ export class FileOnDiskContentProvider implements ITextModelContentProvider {
private resolveEditorModel(resource: URI, createAsNeeded?: true): Promise<ITextModel>;
private resolveEditorModel(resource: URI, createAsNeeded?: boolean): Promise<ITextModel | null>;
private resolveEditorModel(resource: URI, createAsNeeded: boolean = true): Promise<ITextModel | null> {
const savedFileResource = toLocalResource(resource, this.environmentService.configuration.remoteAuthority);
const savedFileResource = fileOnDiskToResource(resource);
return this.textFileService.readStream(savedFileResource).then(content => {
let codeEditorModel = this.modelService.getModel(resource);

View File

@@ -0,0 +1,40 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as assert from 'assert';
import { URI } from 'vs/base/common/uri';
import { workbenchInstantiationService, TestFileService } from 'vs/workbench/test/workbenchTestServices';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { FileOnDiskContentProvider, resourceToFileOnDisk } from 'vs/workbench/contrib/files/common/files';
import { snapshotToString } from 'vs/workbench/services/textfile/common/textfiles';
import { IFileService } from 'vs/platform/files/common/files';
class ServiceAccessor {
constructor(
@IFileService public fileService: TestFileService
) {
}
}
suite('Files - FileOnDiskContentProvider', () => {
let instantiationService: IInstantiationService;
let accessor: ServiceAccessor;
setup(() => {
instantiationService = workbenchInstantiationService();
accessor = instantiationService.createInstance(ServiceAccessor);
});
test('provideTextContent', async () => {
const provider = instantiationService.createInstance(FileOnDiskContentProvider);
const uri = URI.parse('testFileOnDiskContentProvider://foo');
const content = await provider.provideTextContent(resourceToFileOnDisk('conflictResolution', uri));
assert.equal(snapshotToString(content.createSnapshot()), 'Hello Html');
assert.equal(accessor.fileService.getLastReadFileUri().toString(), uri.toString());
});
});