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);
+ };
+}