diff --git a/website/playground/Playground.js b/website/playground/Playground.js index 4192e112..1c9492db 100644 --- a/website/playground/Playground.js +++ b/website/playground/Playground.js @@ -121,7 +121,7 @@ class Playground extends React.Component {
{editorState.showSecondFormat ? ( ) : null}
diff --git a/website/playground/panels.js b/website/playground/panels.js index 72ac0f97..fd5440a0 100644 --- a/website/playground/panels.js +++ b/website/playground/panels.js @@ -7,12 +7,13 @@ class CodeMirrorPanel extends React.Component { this._textareaRef = React.createRef(); this._codeMirror = null; this._cached = ""; + this._overlay = null; this.handleChange = this.handleChange.bind(this); } componentDidMount() { const options = Object.assign({}, this.props); - delete options.rulerColumn; + delete options.ruler; delete options.rulerColor; delete options.value; delete options.onChange; @@ -26,6 +27,7 @@ class CodeMirrorPanel extends React.Component { this._codeMirror.on("change", this.handleChange); this.updateValue(this.props.value || ""); + this.updateOverlay(); } componentWillUnmount() { @@ -35,6 +37,13 @@ class CodeMirrorPanel extends React.Component { componentDidUpdate(prevProps) { if (this.props.readOnly && this.props.value !== this._cached) { this.updateValue(this.props.value); + this.updateOverlay(); + } + if ( + this.props.overlayStart !== prevProps.overlayStart || + this.props.overlayEnd !== this.props.overlayEnd + ) { + this.updateOverlay(); } if (this.props.mode !== prevProps.mode) { this._codeMirror.setOption("mode", this.props.mode); @@ -42,7 +51,7 @@ class CodeMirrorPanel extends React.Component { if (this.props.placeholder !== prevProps.placeholder) { this._codeMirror.setOption("placeholder", this.props.placeholder); } - if (this.props.rulerColumn !== prevProps.rulerColumn) { + if (this.props.ruler !== prevProps.ruler) { this._codeMirror.setOption("rulers", [makeRuler(this.props)]); } } @@ -52,6 +61,20 @@ class CodeMirrorPanel extends React.Component { this._codeMirror.setValue(value); } + updateOverlay() { + if (!this.props.readOnly) { + if (this._overlay) { + this._codeMirror.removeOverlay(this._overlay); + } + const [start, end] = getIndexPosition(this.props.value, [ + this.props.overlayStart, + this.props.overlayEnd + ]); + this._overlay = createOverlay(start, end); + this._codeMirror.addOverlay(this._overlay); + } + } + handleChange(doc, change) { if (change.origin !== "setValue") { this._cached = doc.getValue(); @@ -68,8 +91,56 @@ class CodeMirrorPanel extends React.Component { } } +function getIndexPosition(text, indexes) { + indexes = indexes.slice().sort(); + let line = 0; + let count = 0; + let lineStart = 0; + const result = []; + + while (indexes.length) { + const index = indexes.shift(); + + while (count < index && count < text.length) { + count++; + if (text[count] === "\n") { + line++; + lineStart = count; + } + } + + result.push({ line, pos: count - lineStart }); + } + + return result; +} + +function createOverlay(start, end) { + return { + token(stream) { + const line = stream.lineOracle.line; + + if (line < start.line || line > end.line) { + stream.skipToEnd(); + } else if (line === start.line && stream.pos < start.pos) { + stream.pos = start.pos; + } else if (line === end.line) { + if (stream.pos < end.pos) { + stream.pos = end.pos; + return "searching"; + } else { + stream.skipToEnd(); + } + } else { + stream.skipToEnd(); + return "searching"; + } + } + }; +} + function makeRuler(props) { - return { column: props.rulerColumn, color: props.rulerColor }; + return { column: props.ruler, color: props.rulerColor }; } export function InputPanel(props) { @@ -82,6 +153,8 @@ export function InputPanel(props) { showCursorWhenSelecting={true} tabWidth={2} rulerColor="#eeeeee" + rangeStart={5} + rangeEnd={25} {...props} /> ); @@ -108,3 +181,31 @@ export function DebugPanel({ value }) { /> ); } + +function stringify(obj, replacer, spaces, cycleReplacer) { + return JSON.stringify(obj, serializer(replacer, cycleReplacer), spaces); +} + +function serializer(replacer, cycleReplacer) { + var stack = [], + keys = []; + + if (cycleReplacer == null) + cycleReplacer = function(key, value) { + if (stack[0] === value) return "[Circular ~]"; + return ( + "[Circular ~." + keys.slice(0, stack.indexOf(value)).join(".") + "]" + ); + }; + + return function(key, value) { + if (stack.length > 0) { + var thisPos = stack.indexOf(this); + ~thisPos ? stack.splice(thisPos + 1) : stack.push(this); + ~thisPos ? keys.splice(thisPos, Infinity, key) : keys.push(key); + if (~stack.indexOf(value)) value = cycleReplacer.call(this, key, value); + } else stack.push(value); + + return replacer == null ? value : replacer.call(this, key, value); + }; +}