Skip to content

Commit 6282b4e

Browse files
committed
Fetch the resolved file contents during merge conflict
- TODO: update file with resolved conflicts
1 parent fc54eca commit 6282b4e

File tree

7 files changed

+79
-34
lines changed

7 files changed

+79
-34
lines changed

src/commandsAndMenu.tsx

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -480,18 +480,37 @@ export function addCommands(
480480
tooltip: trans.__('Refresh diff widget'),
481481
className: 'jp-git-diff-refresh'
482482
});
483-
refreshButton.hide();
484-
diffWidget.toolbar.addItem('refresh', refreshButton);
485483

486-
const refresh = () => {
487-
refreshButton.show();
488-
};
489-
490-
model.changed.connect(refresh);
491-
widget.disposed.connect(() => {
492-
model.changed.disconnect(refresh);
484+
const resolveButton = new ToolbarButton({
485+
label: trans.__('Mark as resolved'),
486+
onClick: async () => {
487+
try {
488+
const resolvedFile: string = await widget.getResolvedFile();
489+
// TODO update the file without the conflicts, then close the tab
490+
console.log(resolvedFile);
491+
} catch (reason) {
492+
console.error(reason);
493+
}
494+
},
495+
tooltip: trans.__('Mark file as resolved'),
496+
className: 'jp-git-diff-resolve'
493497
});
494498

499+
// Do not allow the user to refresh during merge conflicts
500+
if (model.isConflict) {
501+
diffWidget.toolbar.addItem('resolve', resolveButton);
502+
} else {
503+
refreshButton.hide();
504+
diffWidget.toolbar.addItem('refresh', refreshButton);
505+
506+
const refresh = () => {
507+
refreshButton.show();
508+
};
509+
510+
model.changed.connect(refresh);
511+
widget.disposed.connect(() => model.changed.disconnect(refresh));
512+
}
513+
495514
// Load the diff widget
496515
modelIsLoading.resolve();
497516
content.addWidget(widget);

src/components/diff/NotebookDiff.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,10 @@ export const createNotebookDiff = async (
9393
/**
9494
* NotebookDiff widget
9595
*/
96-
export class NotebookDiff extends Panel implements Git.Diff.IDiffWidget {
96+
export class NotebookDiff
97+
extends Panel
98+
implements Git.Diff.IDiffWidget<string>
99+
{
97100
constructor(model: Git.Diff.IModel<string>, renderMime: IRenderMimeRegistry) {
98101
super();
99102
const getReady = new PromiseDelegate<void>();
@@ -139,6 +142,10 @@ export class NotebookDiff extends Panel implements Git.Diff.IDiffWidget {
139142
return this._isReady;
140143
}
141144

145+
async getResolvedFile(): Promise<string> {
146+
return Promise.resolve('');
147+
}
148+
142149
/**
143150
* Refresh diff
144151
*

src/components/diff/PlainTextDiff.ts

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { PromiseDelegate } from '@lumino/coreutils';
44
import { Widget } from '@lumino/widgets';
55
import { MergeView } from 'codemirror';
66
import { Git } from '../../tokens';
7-
import { mergeView, MergeView as LocalMergeView } from './mergeview';
7+
import { MergeView as LocalMergeView, mergeView } from './mergeview';
88

99
/**
1010
* Diff callback to be registered for plain-text files.
@@ -25,7 +25,10 @@ export const createPlainTextDiff: Git.Diff.ICallback<string> = async (
2525
/**
2626
* Plain Text Diff widget
2727
*/
28-
export class PlainTextDiff extends Widget implements Git.Diff.IDiffWidget {
28+
export class PlainTextDiff
29+
extends Widget
30+
implements Git.Diff.IDiffWidget<string>
31+
{
2932
constructor(model: Git.Diff.IModel<string>) {
3033
super({
3134
node: PlainTextDiff.createNode(
@@ -72,6 +75,19 @@ export class PlainTextDiff extends Widget implements Git.Diff.IDiffWidget {
7275
return this._isReady;
7376
}
7477

78+
/**
79+
* Gets the file contents of a resolved merge conflict,
80+
* and rejects if unable to retrieve.
81+
*/
82+
getResolvedFile(): Promise<string> {
83+
const value = this._mergeView?.editor().getValue() ?? null;
84+
if (value !== null) {
85+
return Promise.resolve(value);
86+
} else {
87+
return Promise.reject('Failed to get a valid file value.');
88+
}
89+
}
90+
7591
/**
7692
* Callback to create the diff widget once the widget
7793
* is attached so CodeMirror get proper size.

src/components/diff/model.ts

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { Git } from '../../tokens';
66
* Base DiffModel class
77
*/
88
export class DiffModel<T> implements IDisposable, Git.Diff.IModel<T> {
9-
constructor(props: Omit<Git.Diff.IModel<T>, 'changed'>) {
9+
constructor(props: Omit<Git.Diff.IModel<T>, 'changed' | 'isConflict'>) {
1010
this._challenger = props.challenger;
1111
this._filename = props.filename;
1212
this._reference = props.reference;
@@ -84,14 +84,12 @@ export class DiffModel<T> implements IDisposable, Git.Diff.IModel<T> {
8484
get base(): Git.Diff.IContent<T> | undefined {
8585
return this._base;
8686
}
87-
set base(v: Git.Diff.IContent<T>) {
88-
// Only check changes if base is defined
89-
const emitSignal = !this._base || this._didContentChange(this._base, v);
9087

91-
if (emitSignal) {
92-
this._base = v;
93-
this._changed.emit({ type: 'base' });
94-
}
88+
/**
89+
* Helper to check if the file is conflicted.
90+
*/
91+
get isConflict(): boolean {
92+
return !!this._base;
9593
}
9694

9795
/**

src/tokens.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -469,13 +469,18 @@ export namespace Git {
469469
/**
470470
* Diff widget interface
471471
*/
472-
export interface IDiffWidget extends Widget {
472+
export interface IDiffWidget<T> extends Widget {
473473
/**
474474
* Refresh the diff widget
475475
*
476476
* Note: Update the content and recompute the diff
477477
*/
478478
refresh(): Promise<void>;
479+
/**
480+
* Gets the file contents of a resolved merge conflict,
481+
* and rejects if unable to retrieve
482+
*/
483+
getResolvedFile(): Promise<T>;
479484
}
480485

481486
/**
@@ -489,7 +494,7 @@ export namespace Git {
489494
export type ICallback<T> = (
490495
model: IModel<T>,
491496
toolbar?: Toolbar
492-
) => Promise<IDiffWidget>;
497+
) => Promise<IDiffWidget<T>>;
493498

494499
/**
495500
* Content and its context for diff
@@ -562,6 +567,10 @@ export namespace Git {
562567
* Optional base data, used only during merge conflicts
563568
*/
564569
base?: IContent<T>;
570+
/**
571+
* Helper to check if the file is conflicted.
572+
*/
573+
isConflict: boolean;
565574
}
566575

567576
/**

style/diff-common.css

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,18 @@ button.jp-git-diff-refresh {
2626
border: solid 1px var(--jp-warn-color2);
2727
}
2828

29+
button.jp-git-diff-resolve {
30+
border: solid 1px var(--jp-success-color2);
31+
}
32+
2933
button.jp-git-diff-refresh .jp-ToolbarButtonComponent-label {
3034
color: var(--jp-warn-color1);
3135
}
3236

37+
button.jp-git-diff-resolve .jp-ToolbarButtonComponent-label {
38+
color: var(--jp-success-color1);
39+
}
40+
3341
.jp-git-diff-banner {
3442
flex: 0 0 auto;
3543
margin-bottom: 5px;

tests/test-components/DiffModel.spec.tsx

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -55,16 +55,4 @@ describe('DiffModel', () => {
5555

5656
await testChallenger;
5757
});
58-
59-
it('should emit a signal if base changes', async () => {
60-
const testBase = testChangedSignal('base');
61-
62-
model.base = {
63-
content: () => Promise.resolve('content2'),
64-
label: 'base2',
65-
source: 'base2'
66-
};
67-
68-
await testBase;
69-
});
7058
});

0 commit comments

Comments
 (0)