blob: 252f7cb20c5cc1a8214d6e40827c56d36fdaedce [file] [log] [blame]
/**
* @license
* Copyright 2023 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
import {Observable, combineLatest, from} from 'rxjs';
import {switchMap, withLatestFrom} from 'rxjs/operators';
import {
DiffInfo,
DiffPreferencesInfo,
DisplayLine,
RenderPreferences,
} from '../../../api/diff';
import {define} from '../../../models/dependency';
import {Model} from '../../../models/model';
import {select} from '../../../utils/observable-util';
import {
FullContext,
GrDiffCommentThread,
KeyLocations,
computeContext,
computeKeyLocations,
} from '../gr-diff/gr-diff-utils';
import {createDefaultDiffPrefs} from '../../../constants/constants';
import {
GrDiffProcessor,
ProcessingOptions,
} from '../gr-diff-processor/gr-diff-processor';
import {GrDiffGroup} from '../gr-diff/gr-diff-group';
export interface DiffState {
diff: DiffInfo;
path?: string;
renderPrefs: RenderPreferences;
diffPrefs: DiffPreferencesInfo;
lineOfInterest?: DisplayLine;
comments: GrDiffCommentThread[];
groups: GrDiffGroup[];
/** how much context to show for large files */
showFullContext: FullContext;
isImageDiff: boolean;
}
export const diffModelToken = define<DiffModel>('diff-model');
export class DiffModel extends Model<DiffState> {
readonly diff$: Observable<DiffInfo> = select(
this.state$,
diffState => diffState.diff
);
readonly path$: Observable<string | undefined> = select(
this.state$,
diffState => diffState.path
);
readonly renderPrefs$: Observable<RenderPreferences> = select(
this.state$,
diffState => diffState.renderPrefs
);
readonly diffPrefs$: Observable<DiffPreferencesInfo> = select(
this.state$,
diffState => diffState.diffPrefs
);
readonly context$: Observable<number> = select(this.state$, state =>
computeContext(
state.diffPrefs.context,
state.showFullContext,
createDefaultDiffPrefs().context
)
);
readonly isImageDiff$: Observable<boolean> = select(
this.state$,
diffState => diffState.isImageDiff
);
readonly keyLocations$: Observable<KeyLocations> = select(
this.state$,
diffState =>
computeKeyLocations(diffState.lineOfInterest, diffState.comments ?? [])
);
constructor() {
super({
diff: {content: [], change_type: 'MODIFIED', intraline_status: 'OK'},
diffPrefs: createDefaultDiffPrefs(),
renderPrefs: {},
comments: [],
groups: [],
showFullContext: FullContext.UNDECIDED,
isImageDiff: false,
});
this.subscriptions = [this.processDiff()];
}
processDiff() {
return combineLatest([
this.diff$,
this.context$,
this.renderPrefs$,
this.isImageDiff$,
])
.pipe(
withLatestFrom(this.keyLocations$),
switchMap(
([[diff, context, renderPrefs, isImageDiff], keyLocations]) => {
const options: ProcessingOptions = {
context,
keyLocations,
isBinary: !!(isImageDiff || diff.binary),
};
const processor = new GrDiffProcessor(undefined, options);
if (renderPrefs?.num_lines_rendered_at_once) {
options.asyncThreshold = renderPrefs.num_lines_rendered_at_once;
}
return from(processor.process(diff.content));
}
)
)
.subscribe(groups => {
this.updateState({groups});
});
}
}