Skip to content

Commit

Permalink
feat: support merge editor minimap (#2859)
Browse files Browse the repository at this point in the history
* feat: support merge editor minimap

* fix: improve code
  • Loading branch information
Ricbet authored Jul 12, 2023
1 parent 25f6e8c commit 55b3283
Show file tree
Hide file tree
Showing 5 changed files with 151 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import { MappingManagerService } from './mapping-manager.service';
import { IMergeEditorEditorConstructionOptions } from './merge-editor-widget';
import { ComputerDiffModel } from './model/computer-diff';
import { LineRangeMapping } from './model/line-range-mapping';
import { ACCEPT_CURRENT_ACTIONS } from './types';
import { ACCEPT_CURRENT_ACTIONS, IEditorMountParameter } from './types';
import { ActionsManager } from './view/actions-manager';
import { CurrentCodeEditor } from './view/editors/currentCodeEditor';
import { IncomingCodeEditor } from './view/editors/incomingCodeEditor';
Expand Down Expand Up @@ -60,6 +60,9 @@ export class MergeEditorService extends Disposable {
private readonly _onDidInputNutrition = new Emitter<IOpenMergeEditorArgs>();
public readonly onDidInputNutrition: Event<IOpenMergeEditorArgs> = this._onDidInputNutrition.event;

private readonly _onDidMount = new Emitter<IEditorMountParameter>();
public readonly onDidMount: Event<IEditorMountParameter> = this._onDidMount.event;

private readonly _onRestoreState = new Emitter<URI>();
public readonly onRestoreState: Event<URI> = this._onRestoreState.event;

Expand Down Expand Up @@ -105,6 +108,12 @@ export class MergeEditorService extends Disposable {
this.stickinessConnectManager.mount(this.currentView, this.resultView, this.incomingView);
this.actionsManager.mount(this.currentView, this.resultView, this.incomingView);

this._onDidMount.fire({
currentView: this.currentView,
resultView: this.resultView,
incomingView: this.incomingView,
});

this.initListenEvent();
}

Expand Down
7 changes: 7 additions & 0 deletions packages/monaco/src/browser/contrib/merge-editor/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { IModelDecorationOptions } from '../../monaco-api/editor';

import { LineRange } from './model/line-range';
import { LineRangeMapping } from './model/line-range-mapping';
import { BaseCodeEditor } from './view/editors/baseCodeEditor';
import styles from './view/merge-editor.module.less';

export interface IRangeContrast {
Expand Down Expand Up @@ -169,3 +170,9 @@ export interface IMergeEditorViewState {
turnLeft: LineRangeMapping[];
turnRight: LineRangeMapping[];
}

export interface IEditorMountParameter {
currentView: BaseCodeEditor;
resultView: BaseCodeEditor;
incomingView: BaseCodeEditor;
}
15 changes: 13 additions & 2 deletions packages/monaco/src/browser/contrib/merge-editor/view/grid.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { MergeEditorService } from '../merge-editor.service';
import { EditorViewType } from '../types';

import styles from './merge-editor.module.less';
import { MiniMap } from './mini-map';
import { WithViewStickinessConnectComponent } from './stickiness-connect-manager';

const TitleHead: React.FC<{ contrastType: EditorViewType }> = ({ contrastType }) => {
Expand Down Expand Up @@ -159,7 +160,12 @@ export const Grid = () => {
<SplitPanel overflow='hidden' id='merge_editor_container' flex={2}>
<div className={styles.editor_container_arrange}>
<TitleHead contrastType={EditorViewType.CURRENT}></TitleHead>
<div className={styles.editor_container} ref={currentEditorContainer}></div>
<div className={styles.content}>
<div className={styles.minimap_container}>
<MiniMap contrastType={EditorViewType.CURRENT} />
</div>
<div className={styles.editor_container} ref={currentEditorContainer}></div>
</div>
</div>
<div className={styles.editor_container_arrange}>
<TitleHead contrastType={EditorViewType.RESULT}></TitleHead>
Expand All @@ -175,7 +181,12 @@ export const Grid = () => {
</div>
<div className={styles.editor_container_arrange}>
<TitleHead contrastType={EditorViewType.INCOMING}></TitleHead>
<div className={styles.editor_container} ref={incomingEditorContainer}></div>
<div className={styles.content}>
<div className={styles.editor_container} ref={incomingEditorContainer}></div>
<div className={styles.minimap_container}>
<MiniMap contrastType={EditorViewType.INCOMING} />
</div>
</div>
</div>
</SplitPanel>
<MergeActions />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
height: 100%;
overflow: hidden;
position: relative;
padding-left: 8px;

.merge_actions_container {
position: absolute;
Expand Down Expand Up @@ -77,6 +76,40 @@
display: flex;
flex-direction: column;

.content {
height: inherit;
display: flex;

.minimap_container {
height: 100%;
width: 15px;

.minimap_content {
position: relative;
height: inherit;

.block {
position: absolute;
width: 100%;

&.insert {
background-color: var(--mergeEditor-insertedInnerCharColor);
}
&.modify {
background-color: var(--mergeEditor-modifyInnerCharColor);
}
&.remove {
background-color: var(--mergeEditor-removedInnerCharColor);
}
}
}
}

.editor_container {
width: calc(100% - 15px);
}
}

.stickiness_connect_container {
height: 100%;
position: relative;
Expand Down
87 changes: 87 additions & 0 deletions packages/monaco/src/browser/contrib/merge-editor/view/mini-map.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import cls from 'classnames';
import React, { useCallback, useEffect } from 'react';

import { Disposable, Event, useInjectable } from '@opensumi/ide-core-browser';
import { EditorOption } from '@opensumi/monaco-editor-core/esm/vs/editor/common/config/editorOptions';

import { MergeEditorService } from '../merge-editor.service';
import { LineRange } from '../model/line-range';
import { EditorViewType } from '../types';

import { BaseCodeEditor } from './editors/baseCodeEditor';
import styles from './merge-editor.module.less';

interface BlockPiece {
top: string;
height: string;
className: string;
}

export const MiniMap: React.FC<{ contrastType: EditorViewType }> = ({ contrastType }) => {
const mergeEditorService = useInjectable<MergeEditorService>(MergeEditorService);
const [blocks, setBlocks] = React.useState<BlockPiece[]>([]);

useEffect(() => {
const disposables = new Disposable();

disposables.addDispose(
mergeEditorService.onDidMount((data) => {
const { currentView, incomingView } = data;

if (contrastType === EditorViewType.CURRENT) {
disposables.addDispose(
Event.debounce(
currentView.onDidChangeDecorations,
() => {},
1,
)(() => {
computePiece(currentView, currentView.documentMapping.getOriginalRange());
}),
);
} else if (contrastType === EditorViewType.INCOMING) {
disposables.addDispose(
Event.debounce(
incomingView.onDidChangeDecorations,
() => {},
1,
)(() => {
computePiece(incomingView, incomingView.documentMapping.getModifiedRange());
}),
);
}
}),
);

return () => disposables.dispose();
}, [mergeEditorService, contrastType]);

const computePiece = useCallback((viewEditor: BaseCodeEditor, ranges: LineRange[]) => {
const editor = viewEditor.getEditor();

const lineHeight = editor.getOption(EditorOption.lineHeight);
const contentHeight = editor.getContentHeight();
const blocks: BlockPiece[] = [];

ranges.forEach((range) => {
if (range.isComplete) {
return;
}

blocks.push({
top: (((range.startLineNumber - 1) * lineHeight) / contentHeight) * 100 + '%',
height: ((range.length * lineHeight) / contentHeight) * 100 + '%',
className: styles[range.type],
});
});

setBlocks(blocks);
}, []);

return (
<div className={styles.minimap_content}>
{blocks.map((block) => (
<span className={cls(styles.block, block.className)} style={{ top: block.top, height: block.height }}></span>
))}
</div>
);
};

0 comments on commit 55b3283

Please sign in to comment.