Skip to content

Commit

Permalink
fix #5280: synchronize preview with editor when scrolls
Browse files Browse the repository at this point in the history
Signed-off-by: Cai Xuye <a1994846931931@gmail.com>
  • Loading branch information
a1994846931931 authored and AlexTugarev committed Jun 14, 2019
1 parent 8b52995 commit f1c23e2
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 2 deletions.
3 changes: 3 additions & 0 deletions packages/editor/src/browser/editor.ts
Expand Up @@ -168,6 +168,9 @@ export interface TextEditor extends Disposable, TextEditorSelection, Navigatable

readonly onMouseDown: Event<EditorMouseEvent>;

readonly onScrollChanged: Event<void>;
getVisibleRanges(): Range[];

revealPosition(position: Position, options?: RevealPositionOptions): void;
revealRange(range: Range, options?: RevealRangeOptions): void;

Expand Down
15 changes: 14 additions & 1 deletion packages/monaco/src/browser/monaco-editor.ts
Expand Up @@ -62,6 +62,7 @@ export class MonacoEditor implements TextEditor {
protected readonly onMouseDownEmitter = new Emitter<EditorMouseEvent>();
protected readonly onLanguageChangedEmitter = new Emitter<string>();
readonly onLanguageChanged = this.onLanguageChangedEmitter.event;
protected readonly onScrollChangedEmitter = new Emitter<void>();

readonly documents = new Set<MonacoEditorModel>();

Expand All @@ -80,7 +81,8 @@ export class MonacoEditor implements TextEditor {
this.onFocusChangedEmitter,
this.onDocumentContentChangedEmitter,
this.onMouseDownEmitter,
this.onLanguageChangedEmitter
this.onLanguageChangedEmitter,
this.onScrollChangedEmitter
]);
this.documents.add(document);
this.autoSizing = options && options.autoSizing !== undefined ? options.autoSizing : false;
Expand Down Expand Up @@ -139,6 +141,13 @@ export class MonacoEditor implements TextEditor {
event: e.event.browserEvent
});
}));
this.toDispose.push(codeEditor.onDidScrollChange(e => {
this.onScrollChangedEmitter.fire(undefined);
}));
}

getVisibleRanges(): Range[] {
return this.editor.getVisibleRanges().map(range => this.m2p.asRange(range));
}

protected mapModelContentChange(change: monaco.editor.IModelContentChange): TextDocumentContentChangeDelta {
Expand Down Expand Up @@ -184,6 +193,10 @@ export class MonacoEditor implements TextEditor {
return this.onSelectionChangedEmitter.event;
}

get onScrollChanged(): Event<void> {
return this.onScrollChangedEmitter.event;
}

revealPosition(raw: Position, options: RevealPositionOptions = { vertical: 'center' }): void {
const position = this.p2m.asPosition(raw);
switch (options.vertical) {
Expand Down
31 changes: 30 additions & 1 deletion packages/preview/src/browser/preview-contribution.ts
Expand Up @@ -67,6 +67,10 @@ export class PreviewContribution extends NavigatableWidgetOpenHandler<PreviewWid

protected readonly synchronizedUris = new Set<string>();

protected scrollSyncLockOn: 'preview' | 'editor' | undefined = undefined;

protected scrollSyncLockTimeout: number | undefined;

onStart() {
this.onCreated(previewWidget => {
this.registerOpenOnDoubleClick(previewWidget);
Expand All @@ -77,6 +81,16 @@ export class PreviewContribution extends NavigatableWidgetOpenHandler<PreviewWid
});
}

protected async lockScrollSync(on: 'preview' | 'editor', delay: number = 50) {
this.scrollSyncLockOn = on;
if (this.scrollSyncLockTimeout) {
window.clearTimeout(this.scrollSyncLockTimeout);
}
this.scrollSyncLockTimeout = window.setTimeout(() => {
this.scrollSyncLockOn = undefined;
}, delay);
}

protected async registerEditorAndPreviewSync(source: PreviewWidget | EditorWidget): Promise<void> {
let uri: string;
let editorWidget: EditorWidget | undefined;
Expand All @@ -101,7 +115,17 @@ export class PreviewContribution extends NavigatableWidgetOpenHandler<PreviewWid
editorWidget.disposed.connect(() => syncDisposables.dispose());

const editor = editorWidget.editor;
syncDisposables.push(editor.onCursorPositionChanged(debounce(position => this.revealSourceLineInPreview(previewWidget!, position)), 100));
syncDisposables.push(editor.onScrollChanged(debounce(() => {
if (this.scrollSyncLockOn === 'editor') {
// avoid recursive scroll synchronization
return;
}
this.lockScrollSync('preview');
const range = editor.getVisibleRanges();
if (range.length > 0) {
this.revealSourceLineInPreview(previewWidget!, range[0].start);
}
}), 100));
syncDisposables.push(this.synchronizeScrollToEditor(previewWidget, editor));

this.synchronizedUris.add(uri);
Expand All @@ -114,7 +138,12 @@ export class PreviewContribution extends NavigatableWidgetOpenHandler<PreviewWid

protected synchronizeScrollToEditor(previewWidget: PreviewWidget, editor: TextEditor): Disposable {
return previewWidget.onDidScroll(sourceLine => {
if (this.scrollSyncLockOn === 'preview') {
// avoid recursive scroll synchronization
return;
}
const line = Math.floor(sourceLine);
this.lockScrollSync('editor'); // avoid recursive scroll synchronization
editor.revealRange({
start: {
line,
Expand Down

0 comments on commit f1c23e2

Please sign in to comment.