Skip to content

Commit

Permalink
feat: render conflict actions (#2002)
Browse files Browse the repository at this point in the history
* feat: implement conflict actions base code

* chore: improve code
  • Loading branch information
Ricbet committed Dec 27, 2022
1 parent 48075c1 commit 7935278
Show file tree
Hide file tree
Showing 13 changed files with 319 additions and 24 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { Disposable, MonacoService } from '@opensumi/ide-core-browser';
import { ICodeEditor } from '../../monaco-api/editor';

import { ComputerDiffModel } from './model/computer-diff';
import { ActionsManager } from './view/actions-manager';
import { CurrentCodeEditor } from './view/editors/currentCodeEditor';
import { IncomingCodeEditor } from './view/editors/incomingCodeEditor';
import { ResultCodeEditor } from './view/editors/resultCodeEditor';
Expand All @@ -23,6 +24,7 @@ export class MergeEditorService extends Disposable {
private incomingView: IncomingCodeEditor;

private computerDiffModel: ComputerDiffModel;
private actionsManager: ActionsManager;

public scrollSynchronizer: ScrollSynchronizer;
public stickinessConnectManager: StickinessConnectManager;
Expand All @@ -32,6 +34,7 @@ export class MergeEditorService extends Disposable {
this.computerDiffModel = new ComputerDiffModel();
this.scrollSynchronizer = new ScrollSynchronizer();
this.stickinessConnectManager = new StickinessConnectManager();
this.actionsManager = new ActionsManager();
}

public instantiationCodeEditor(current: HTMLDivElement, result: HTMLDivElement, incoming: HTMLDivElement): void {
Expand All @@ -45,6 +48,7 @@ export class MergeEditorService extends Disposable {

this.scrollSynchronizer.mount(this.currentView, this.resultView, this.incomingView);
this.stickinessConnectManager.mount(this.currentView, this.resultView, this.incomingView);
this.actionsManager.mount(this.currentView, this.resultView, this.incomingView);
}

public override dispose(): void {
Expand All @@ -54,6 +58,7 @@ export class MergeEditorService extends Disposable {
this.incomingView.dispose();
this.scrollSynchronizer.dispose();
this.stickinessConnectManager.dispose();
this.actionsManager.dispose();
}

public getCurrentEditor(): ICodeEditor {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { Injectable, Optional } from '@opensumi/di';
import { Disposable } from '@opensumi/ide-core-common';
import { IEditorDecorationsCollection } from '@opensumi/monaco-editor-core/esm/vs/editor/common/editorCommon';
import { ModelDecorationOptions } from '@opensumi/monaco-editor-core/esm/vs/editor/common/model/textModel';

import { ICodeEditor, IModelDeltaDecoration } from '../../../monaco-api/editor';
import { IActionsDescription } from '../types';
import { BaseCodeEditor } from '../view/editors/baseCodeEditor';

import { LineRange } from './line-range';

@Injectable({ multiple: false })
export class ConflictActions extends Disposable {
private decorationsCollection: IEditorDecorationsCollection;
private actionsCollect: Map<number, LineRange>;

private get editor(): ICodeEditor {
return this.codeEditor.getEditor();
}

constructor(@Optional() private readonly codeEditor: BaseCodeEditor) {
super();

this.decorationsCollection = this.editor.createDecorationsCollection();
this.actionsCollect = new Map();
}

public override dispose(): void {
super.dispose();
this.decorationsCollection.clear();
this.actionsCollect.clear();
}

public setActions(actions: IActionsDescription[]): void {
const newDecorations: IModelDeltaDecoration[] = actions.map((action) => {
const { range } = action;
this.actionsCollect.set(range.startLineNumber, range);

return {
range: {
startLineNumber: range.startLineNumber,
startColumn: 0,
endLineNumber: range.startLineNumber,
endColumn: 0,
},
options: ModelDecorationOptions.register(action.decorationOptions),
};
});

this.decorationsCollection.set(newDecorations);
}

public getActions(line: number): LineRange | undefined {
return this.actionsCollect.get(line);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export interface IDiffDecoration {
readonly editorDecoration: IModelDeltaDecoration;
}

@Injectable({ multiple: true })
@Injectable({ multiple: false })
export class MergeEditorDecorations extends Disposable {
private deltaDecoration: IDiffDecoration[] = [];
private retainDecoration: IDiffDecoration[] = [];
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { IRange } from '@opensumi/monaco-editor-core';
import { Range } from '@opensumi/monaco-editor-core/esm/vs/editor/common/core/range';
import { LineRange as MonacoLineRange } from '@opensumi/monaco-editor-core/esm/vs/editor/common/diff/linesDiffComputer';

export class LineRange extends MonacoLineRange {
Expand All @@ -12,4 +14,11 @@ export class LineRange extends MonacoLineRange {
public isTendencyLeft(refer: LineRange): boolean {
return !this.isEmpty && refer.isEmpty;
}

public toIRange(): IRange {
return Range.fromPositions(
{ lineNumber: this.startLineNumber, column: 0 },
{ lineNumber: this.endLineNumberExclusive - 1, column: 0 },
);
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import clone from 'lodash/clone';

import { IStickyPiece, IStickyPiecePath, IStickyPiecePosition, LineRangeType } from '../types';

export class StickyPieceModel implements IStickyPiece {
Expand Down
40 changes: 40 additions & 0 deletions packages/monaco/src/browser/contrib/merge-editor/types.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,14 @@
import { getIcon } from '@opensumi/ide-core-browser';
import { IEditorMouseEvent } from '@opensumi/monaco-editor-core/esm/vs/editor/browser/editorBrowser';

import { IModelDecorationOptions } from '../../monaco-api/editor';

import { LineRange } from './model/line-range';

export interface IBaseCodeEditor {
mount(): void;
}

export type LineRangeType = 'insert' | 'modify' | 'remove';

export type EditorViewType = 'current' | 'result' | 'incoming';
Expand All @@ -20,3 +31,32 @@ export interface IStickyPiece {
position: IStickyPiecePosition;
path: IStickyPiecePath;
}

export interface IActionsDescription {
range: LineRange;
decorationOptions: IModelDecorationOptions;
}

export const ACCEPT_CURRENT = 'accpet_current';
export const ACCEPT_COMBINATION = 'accpet_combination';
export const IGNORE = 'ignore';

export interface IActionsProvider {
onActionsClick?: (
e: IEditorMouseEvent,
currentView: IBaseCodeEditor,
resultView: IBaseCodeEditor,
incomingView: IBaseCodeEditor,
) => void;
mouseDownGuard?: (e: IEditorMouseEvent) => boolean;
/**
* 提供 actions 操作项
*/
provideActionsItems: () => IActionsDescription[];
}

export namespace CONFLICT_ACTIONS_ICON {
export const RIGHT = `conflict-actions ${ACCEPT_CURRENT} ${getIcon('right')}`;
export const LEFT = `conflict-actions ${ACCEPT_CURRENT} ${getIcon('left')}`;
export const CLOSE = `conflict-actions ${IGNORE} ${getIcon('close')}`;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import { Disposable } from '@opensumi/ide-core-common';
import { IEditorMouseEvent, MouseTargetType } from '@opensumi/monaco-editor-core/esm/vs/editor/browser/editorBrowser';

import { IActionsDescription } from '../types';

import { BaseCodeEditor } from './editors/baseCodeEditor';

export class ActionsManager extends Disposable {
private currentView: BaseCodeEditor | undefined;
private resultView: BaseCodeEditor | undefined;
private incomingView: BaseCodeEditor | undefined;

constructor() {
super();
}

public mount(currentView: BaseCodeEditor, resultView: BaseCodeEditor, incomingView: BaseCodeEditor): void {
this.currentView = currentView;
this.resultView = resultView;
this.incomingView = incomingView;

const handleMouseDown = (e: IEditorMouseEvent, _this: BaseCodeEditor) => {
const provider = _this.actionsProvider;
if (!provider) {
return;
}

let { mouseDownGuard } = provider;
const { onActionsClick, provideActionsItems } = provider;

if (typeof mouseDownGuard === 'undefined') {
const items = provideActionsItems();
mouseDownGuard = (e: IEditorMouseEvent) => {
if (e.event.rightButton) {
return false;
}

if (e.target.type !== MouseTargetType.GUTTER_LINE_DECORATIONS) {
return false;
}

const { position } = e.target;

if (!items.some((item: IActionsDescription) => item.range.startLineNumber === position.lineNumber)) {
return false;
}

return true;
};
}

if (mouseDownGuard(e) === true && onActionsClick) {
onActionsClick.call(_this, e, currentView, resultView, incomingView);
}
};

this.addDispose(currentView.getEditor().onMouseDown((e: IEditorMouseEvent) => handleMouseDown(e, currentView)));
this.addDispose(incomingView.getEditor().onMouseDown((e: IEditorMouseEvent) => handleMouseDown(e, incomingView)));
this.addDispose(resultView.getEditor().onMouseDown((e: IEditorMouseEvent) => handleMouseDown(e, resultView)));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,28 @@ import { Injector } from '@opensumi/di';
import { MonacoService } from '@opensumi/ide-core-browser';
import { Disposable, Event } from '@opensumi/ide-core-common';
import { ICodeEditor } from '@opensumi/monaco-editor-core/esm/vs/editor/browser/editorBrowser';
import { EditorLayoutInfo } from '@opensumi/monaco-editor-core/esm/vs/editor/common/config/editorOptions';
import { EditorLayoutInfo, EditorOption } from '@opensumi/monaco-editor-core/esm/vs/editor/common/config/editorOptions';
import { Range } from '@opensumi/monaco-editor-core/esm/vs/editor/common/core/range';
import { LineRangeMapping } from '@opensumi/monaco-editor-core/esm/vs/editor/common/diff/linesDiffComputer';
import { IModelDecorationOptions, ITextModel } from '@opensumi/monaco-editor-core/esm/vs/editor/common/model';
import { IStandaloneEditorConstructionOptions } from '@opensumi/monaco-editor-core/esm/vs/editor/standalone/browser/standaloneCodeEditor';

import { ConflictActions } from '../../model/conflict-actions';
import {
IDiffDecoration,
IRenderChangesInput,
IRenderInnerChangesInput,
MergeEditorDecorations,
} from '../../model/decorations';
import { LineRange } from '../../model/line-range';
import { EditorViewType } from '../../types';
import { EditorViewType, IActionsProvider, IBaseCodeEditor } from '../../types';
import { flatModified, flatOriginal } from '../../utils';
import { GuidelineWidget } from '../guideline-widget';

export abstract class BaseCodeEditor extends Disposable {
export abstract class BaseCodeEditor extends Disposable implements IBaseCodeEditor {
#actionsProvider: IActionsProvider | undefined;
#conflictActions: ConflictActions;

protected decorations: MergeEditorDecorations;
protected editor: ICodeEditor;

Expand All @@ -36,6 +40,7 @@ export abstract class BaseCodeEditor extends Disposable {
super.dispose();
this.editor.dispose();
this.decorations.dispose();
this.#conflictActions.dispose();
}

public mount(): void {
Expand All @@ -53,6 +58,7 @@ export abstract class BaseCodeEditor extends Disposable {
});

this.decorations = this.injector.get(MergeEditorDecorations, [this, this.getEditorViewType()]);
this.#conflictActions = this.injector.get(ConflictActions, [this]);

this.addDispose(
Event.debounce(
Expand All @@ -63,13 +69,15 @@ export abstract class BaseCodeEditor extends Disposable {
() => {},
0,
)(() => {
const marginWith = this.editor.getLayoutInfo().contentLeft;
const lineDecorationsWidth = this.editor.getOption(EditorOption.lineDecorationsWidth);
const contentLeft = this.editor.getLayoutInfo().contentLeft;
const marginWidth = contentLeft - (typeof lineDecorationsWidth === 'number' ? lineDecorationsWidth : 0);
const widgets = this.decorations.getLineWidgets();
if (widgets.length > 0) {
widgets.forEach((w) => {
if (w) {
w.setContainerStyle({
left: marginWith + 'px',
left: marginWidth + 'px',
});
}
});
Expand Down Expand Up @@ -150,6 +158,21 @@ export abstract class BaseCodeEditor extends Disposable {
.updateDecorations(r, i);
}

protected registerActionsProvider(provider: IActionsProvider): void {
if (this.#actionsProvider) {
return;
}

this.#actionsProvider = provider;

const { provideActionsItems } = provider;
this.#conflictActions.setActions(provideActionsItems());
}

public get actionsProvider(): IActionsProvider | undefined {
return this.#actionsProvider;
}

public clearDecorations(): void {
this.decorations.clearDecorations();
}
Expand Down
Loading

0 comments on commit 7935278

Please sign in to comment.