Path: blob/main/extensions/merge-conflict/src/documentMergeConflict.ts
3296 views
/*---------------------------------------------------------------------------------------------1* Copyright (c) Microsoft Corporation. All rights reserved.2* Licensed under the MIT License. See License.txt in the project root for license information.3*--------------------------------------------------------------------------------------------*/4import * as interfaces from './interfaces';5import * as vscode from 'vscode';6import type TelemetryReporter from '@vscode/extension-telemetry';78export class DocumentMergeConflict implements interfaces.IDocumentMergeConflict {910public range: vscode.Range;11public current: interfaces.IMergeRegion;12public incoming: interfaces.IMergeRegion;13public commonAncestors: interfaces.IMergeRegion[];14public splitter: vscode.Range;15private applied = false;1617constructor(descriptor: interfaces.IDocumentMergeConflictDescriptor, private readonly telemetryReporter: TelemetryReporter) {18this.range = descriptor.range;19this.current = descriptor.current;20this.incoming = descriptor.incoming;21this.commonAncestors = descriptor.commonAncestors;22this.splitter = descriptor.splitter;23}2425public commitEdit(type: interfaces.CommitType, editor: vscode.TextEditor, edit?: vscode.TextEditorEdit): Thenable<boolean> {26function commitTypeToString(type: interfaces.CommitType): string {27switch (type) {28case interfaces.CommitType.Current:29return 'current';30case interfaces.CommitType.Incoming:31return 'incoming';32case interfaces.CommitType.Both:33return 'both';34}35}3637/* __GDPR__38"mergeMarkers.accept" : {39"owner": "hediet",40"comment": "Used to understand how the inline merge editor experience is used.",41"resolution": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "comment": "Indicates how the merge conflict was resolved by the user" }42}43*/44this.telemetryReporter.sendTelemetryEvent('mergeMarkers.accept', { resolution: commitTypeToString(type) });4546if (edit) {4748this.applyEdit(type, editor.document, edit);49return Promise.resolve(true);50}5152return editor.edit((edit) => this.applyEdit(type, editor.document, edit));53}5455public applyEdit(type: interfaces.CommitType, document: vscode.TextDocument, edit: { replace(range: vscode.Range, newText: string): void }): void {56if (this.applied) {57return;58}59this.applied = true;6061// Each conflict is a set of ranges as follows, note placements or newlines62// which may not in spans63// [ Conflict Range -- (Entire content below)64// [ Current Header ]\n -- >>>>> Header65// [ Current Content ] -- (content)66// [ Splitter ]\n -- =====67// [ Incoming Content ] -- (content)68// [ Incoming Header ]\n -- <<<<< Incoming69// ]70if (type === interfaces.CommitType.Current) {71// Replace [ Conflict Range ] with [ Current Content ]72const content = document.getText(this.current.content);73this.replaceRangeWithContent(content, edit);74}75else if (type === interfaces.CommitType.Incoming) {76const content = document.getText(this.incoming.content);77this.replaceRangeWithContent(content, edit);78}79else if (type === interfaces.CommitType.Both) {80// Replace [ Conflict Range ] with [ Current Content ] + \n + [ Incoming Content ]8182const currentContent = document.getText(this.current.content);83const incomingContent = document.getText(this.incoming.content);8485edit.replace(this.range, currentContent.concat(incomingContent));86}87}8889private replaceRangeWithContent(content: string, edit: { replace(range: vscode.Range, newText: string): void }) {90if (this.isNewlineOnly(content)) {91edit.replace(this.range, '');92return;93}9495// Replace [ Conflict Range ] with [ Current Content ]96edit.replace(this.range, content);97}9899private isNewlineOnly(text: string) {100return text === '\n' || text === '\r\n';101}102}103104105