Merge pull request #18997 from mjbvz/md-scroll-editor-on-scroll-preview

Add Markdown Preview to Editor Scroll Syncronization
This commit is contained in:
Alexandru Dima 2017-01-23 16:47:39 +01:00 committed by GitHub
commit e40b04faf8
11 changed files with 107 additions and 33 deletions

View file

@ -77,23 +77,17 @@
}
}
function didUpdateScrollPosition(offset) {
function getEditorLineNumberForPageOffset(offset) {
const {previous, next} = getLineElementsAtPageOffset(offset);
if (previous) {
let line = 0;
if (next) {
const betweenProgress = (offset - window.scrollY - previous.element.getBoundingClientRect().top) / (next.element.getBoundingClientRect().top - previous.element.getBoundingClientRect().top);
line = previous.line + Math.floor(betweenProgress * (next.line - previous.line));
return previous.line + betweenProgress * (next.line - previous.line);
} else {
line = previous.line;
return previous.line;
}
const args = [window.initialData.source, line];
window.parent.postMessage({
command: "did-click-link",
data: `command:_markdown.didClick?${encodeURIComponent(JSON.stringify(args))}`
}, "file://");
}
return null;
}
@ -119,6 +113,7 @@
}
}
var scrollDisabled = false;
var pageHeight = 0;
var marker = new ActiveLineMarker();
@ -127,6 +122,7 @@
if (window.initialData.enablePreviewSync) {
const initialLine = +window.initialData.line || 0;
scrollDisabled = true;
scrollToRevealSourceLine(initialLine);
}
};
@ -144,19 +140,38 @@
window.addEventListener('message', event => {
const line = +event.data.line;
if (!isNaN(line)) {
scrollDisabled = true;
scrollToRevealSourceLine(line);
}
}, false);
document.ondblclick = (e) => {
const offset = e.pageY;
didUpdateScrollPosition(offset);
const line = getEditorLineNumberForPageOffset(offset);
if (!isNaN(line)) {
const args = [window.initialData.source, line];
window.parent.postMessage({
command: "did-click-link",
data: `command:_markdown.didClick?${encodeURIComponent(JSON.stringify(args))}`
}, "file://");
}
};
/**
window.onscroll = () => {
didUpdateScrollPosition(window.scrollY);
};
*/
if (window.initialData.enableScrollSync) {
window.onscroll = () => {
if (scrollDisabled) {
scrollDisabled = false;
} else {
const line = getEditorLineNumberForPageOffset(window.scrollY);
if (!isNaN(line)) {
const args = [window.initialData.source, line];
window.parent.postMessage({
command: "did-click-link",
data: `command:_markdown.revealLine?${encodeURIComponent(JSON.stringify(args))}`
}, "file://");
}
}
};
}
}
}());

View file

@ -152,6 +152,11 @@
"type": "boolean",
"default": true,
"description": "%markdown.preview.experimentalSyncronizationEnabled.desc%"
},
"markdown.preview.synchronizePreviewScrollingToEditor": {
"type": "boolean",
"default": true,
"description": "%markdown.preview.synchronizePreviewScrollingToEditor.desc%"
}
}
}

View file

@ -7,5 +7,6 @@
"markdown.preview.fontFamily.desc": "Controls the font family used in the markdown preview.",
"markdown.preview.fontSize.desc": "Controls the font size in pixels used in the markdown preview.",
"markdown.preview.lineHeight.desc": "Controls the line height used in the markdown preview. This number is relative to the font size.",
"markdown.preview.experimentalSyncronizationEnabled.desc": "Enable experimental syncronization between the markdown preview and the editor"
"markdown.preview.experimentalSyncronizationEnabled.desc": "Enable experimental syncronization between the markdown preview and the editor",
"markdown.preview.synchronizePreviewScrollingToEditor.desc": "When the preview is scrolled, update the view of the editor"
}

View file

@ -40,10 +40,26 @@ export function activate(context: vscode.ExtensionContext) {
context.subscriptions.push(vscode.commands.registerCommand('markdown.showPreviewToSide', uri => showPreview(uri, true)));
context.subscriptions.push(vscode.commands.registerCommand('markdown.showSource', showSource));
context.subscriptions.push(vscode.commands.registerCommand('_markdown.revealLine', (uri, line) => {
const sourceUri = vscode.Uri.parse(decodeURIComponent(uri));
vscode.window.visibleTextEditors
.filter(editor => editor.document.uri.path === sourceUri.path)
.forEach(editor => {
const sourceLine = Math.floor(line);
const text = editor.document.getText(new vscode.Range(sourceLine, 0, sourceLine + 1, 0));
const fraction = line - Math.floor(line);
const start = fraction * text.length;
editor.revealRange(
new vscode.Range(sourceLine, start, sourceLine + 1, 0),
vscode.TextEditorRevealType.AtTop);
});
}));
context.subscriptions.push(vscode.commands.registerCommand('_markdown.didClick', (uri, line) => {
return vscode.workspace.openTextDocument(vscode.Uri.parse(decodeURIComponent(uri)))
const sourceUri = vscode.Uri.parse(decodeURIComponent(uri));
return vscode.workspace.openTextDocument(sourceUri)
.then(document => vscode.window.showTextDocument(document))
.then(editor => vscode.commands.executeCommand('revealLine', { lineNumber: line, at: 'top' }));
.then(editor => vscode.commands.executeCommand('revealLine', { lineNumber: Math.floor(line), at: 'top' }));
}));
context.subscriptions.push(vscode.workspace.onDidSaveTextDocument(document => {
@ -246,8 +262,9 @@ class MDDocumentContentProvider implements vscode.TextDocumentContentProvider {
return vscode.workspace.openTextDocument(sourceUri).then(document => {
const scrollBeyondLastLine = vscode.workspace.getConfiguration('editor')['scrollBeyondLastLine'];
const wordWrap = vscode.workspace.getConfiguration('editor')['wordWrap'];
const enablePreviewSync = vscode.workspace.getConfiguration('markdown').get('preview.experimentalSyncronizationEnabled', true);
const previewFrontMatter = vscode.workspace.getConfiguration('markdown')['previewFrontMatter'];
const markdownConfig = vscode.workspace.getConfiguration('markdown');
const previewFrontMatter = markdownConfig.get('previewFrontMatter', 'hide');
let initialLine = 0;
const editor = vscode.window.activeTextEditor;
@ -273,7 +290,8 @@ class MDDocumentContentProvider implements vscode.TextDocumentContentProvider {
window.initialData = {
source: "${encodeURIComponent(sourceUri.scheme + '://' + sourceUri.path)}",
line: ${initialLine},
enablePreviewSync: ${!!enablePreviewSync}
enablePreviewSync: ${!!markdownConfig.get('preview.experimentalSyncronizationEnabled', true)},
enableScrollSync: ${!!markdownConfig.get('preview.synchronizePreviewScrollingToEditor', true)}
};
</script>
<script src="${this.getMediaPath('main.js')}"></script>

View file

@ -612,6 +612,10 @@ export class DiffEditorWidget extends EventEmitter implements editorBrowser.IDif
this.modifiedEditor.revealRangeInCenterIfOutsideViewport(range);
}
public revealRangeAtTop(range: editorCommon.IRange): void {
this.modifiedEditor.revealRangeAtTop(range);
}
public _addAction(descriptor: editorCommon.IActionDescriptor): IAddedAction {
return this.modifiedEditor._addAction(descriptor);
}

View file

@ -460,6 +460,14 @@ export abstract class CommonCodeEditor extends EventEmitter implements editorCom
);
}
public revealRangeAtTop(range: editorCommon.IRange): void {
this._revealRange(
range,
editorCommon.VerticalRevealType.Top,
true
);
}
private _revealRange(range: editorCommon.IRange, verticalType: editorCommon.VerticalRevealType, revealHorizontal: boolean): void {
if (!Range.isIRange(range)) {
throw new Error('Invalid arguments');

View file

@ -3619,6 +3619,11 @@ export interface IEditor {
*/
revealRangeInCenter(range: IRange): void;
/**
* Scroll vertically or horizontally as necessary and reveal a range at the top of the viewport.
*/
revealRangeAtTop(range: IRange): void;
/**
* Scroll vertically or horizontally as necessary and reveal a range centered vertically only if it lies outside the viewport.
*/

4
src/vs/monaco.d.ts vendored
View file

@ -3007,6 +3007,10 @@ declare module monaco.editor {
* Scroll vertically or horizontally as necessary and reveal a range centered vertically.
*/
revealRangeInCenter(range: IRange): void;
/**
* Scroll vertically or horizontally as necessary and reveal a range at the top of the viewport.
*/
revealRangeAtTop(range: IRange): void;
/**
* Scroll vertically or horizontally as necessary and reveal a range centered vertically only if it lies outside the viewport.
*/

6
src/vs/vscode.d.ts vendored
View file

@ -651,7 +651,11 @@ declare module 'vscode' {
* If the range is outside the viewport, it will be revealed in the center of the viewport.
* Otherwise, it will be revealed with as little scrolling as possible.
*/
InCenterIfOutsideViewport = 2
InCenterIfOutsideViewport = 2,
/**
* The range will always be revealed at the top of the viewport.
*/
AtTop = 3
}
/**

View file

@ -920,7 +920,8 @@ export enum TextDocumentSaveReason {
export enum TextEditorRevealType {
Default = 0,
InCenter = 1,
InCenterIfOutsideViewport = 2
InCenterIfOutsideViewport = 2,
AtTop = 3
}
export enum TextEditorSelectionChangeKind {

View file

@ -56,7 +56,8 @@ export interface IFocusTracker {
export enum TextEditorRevealType {
Default = 0,
InCenter = 1,
InCenterIfOutsideViewport = 2
InCenterIfOutsideViewport = 2,
AtTop = 3
}
export interface IUndoStopOptions {
@ -288,14 +289,22 @@ export class MainThreadTextEditor {
console.warn('revealRange on invisible editor');
return;
}
if (revealType === TextEditorRevealType.Default) {
this._codeEditor.revealRange(range);
} else if (revealType === TextEditorRevealType.InCenter) {
this._codeEditor.revealRangeInCenter(range);
} else if (revealType === TextEditorRevealType.InCenterIfOutsideViewport) {
this._codeEditor.revealRangeInCenterIfOutsideViewport(range);
} else {
console.warn('Unknown revealType');
switch (revealType) {
case TextEditorRevealType.Default:
this._codeEditor.revealRange(range);
break;
case TextEditorRevealType.InCenter:
this._codeEditor.revealRangeInCenter(range);
break;;
case TextEditorRevealType.InCenterIfOutsideViewport:
this._codeEditor.revealRangeInCenterIfOutsideViewport(range);
break;
case TextEditorRevealType.AtTop:
this._codeEditor.revealRangeAtTop(range);
break;
default:
console.warn('Unknown revealType');
break;
}
}