diff --git a/Public/css/highlight.css b/Public/css/highlight.css
index 0040fac..6ac380a 100644
--- a/Public/css/highlight.css
+++ b/Public/css/highlight.css
@@ -84,13 +84,23 @@
.exp-special {
color: #c0c;
}
-span.match {
+
+span.match-char {
background: rgba(112, 176, 224, 0.5);
color: #101112;
border-right: solid 1px #ffffff;
border-left: solid 1px #ffffff;
margin-right: -2px;
}
+span.match-left {
+ border-left: solid 2px rgba(255, 0, 0, 0.2);
+ margin-left: -2px;
+}
+span.match-right {
+ border-right: solid 2px rgba(255, 0, 0, 0.2);
+ margin-right: -2px;
+}
+
span.error {
color: #d22;
font-weight: 700;
diff --git a/Public/js/views/test_highlighter.js b/Public/js/views/test_highlighter.js
index 4617d4f..c332b04 100644
--- a/Public/js/views/test_highlighter.js
+++ b/Public/js/views/test_highlighter.js
@@ -7,8 +7,12 @@ import Utils from "../misc/utils";
export default class TestHighlighter extends EventDispatcher {
constructor(editor) {
super();
+
this.editor = editor;
this.activeMarks = [];
+ this.widgets = [];
+
+ this.textHeight = editor.defaultTextHeight();
}
draw(tokens) {
@@ -20,13 +24,6 @@ export default class TestHighlighter extends EventDispatcher {
const marks = this.activeMarks;
for (const token of tokens) {
- const className = "match";
- const location = Editor.calcRangePos(
- this.editor,
- token.location.start,
- token.location.end - token.location.start
- );
-
const match = Utils.htmlSafe(token.value);
let tooltip = `
match: ${match}
@@ -38,22 +35,101 @@ export default class TestHighlighter extends EventDispatcher {
for (const [i, capture] of token.captures.entries()) {
const value = Utils.htmlSafe(capture.value || "");
tooltip += `
-
group #${i + 1}: ${value}
+
group #${i + 1}: ${
+ value === "" ? "empty string" : value
+ }
`;
}
}
- marks.push(
- doc.markText(location.startPos, location.endPos, {
- className: className,
- attributes: {
- "data-tippy-content": tooltip,
- },
- })
- );
+
+ if (token.location.start < token.location.end) {
+ const location = Editor.calcRangePos(
+ editor,
+ token.location.start,
+ token.location.end - token.location.start
+ );
+ marks.push(
+ doc.markText(location.startPos, location.endPos, {
+ className: "match-char",
+ attributes: {
+ "data-tippy-content": tooltip,
+ },
+ })
+ );
+ } else {
+ const location = Editor.calcRangePos(editor, token.location.start, 1);
+
+ if (
+ location.startPos.line === location.endPos.line &&
+ location.startPos.ch === location.endPos.ch
+ ) {
+ this.addLeftAnchor(location, { "data-tippy-content": tooltip });
+ }
+ if (location.startPos.line === location.endPos.line) {
+ if (location.startPos.ch < location.endPos.ch) {
+ marks.push(
+ doc.markText(location.startPos, location.endPos, {
+ className: "match-left",
+ attributes: {
+ "data-tippy-content": tooltip,
+ },
+ })
+ );
+ } else {
+ // this.addRightAnchor(location, { "data-tippy-content": tooltip });
+ }
+ } else {
+ if (location.startPos.ch === 0 && location.endPos.ch === 0) {
+ this.addLeftAnchor(location, { "data-tippy-content": tooltip });
+ } else {
+ this.addRightAnchor(location, { "data-tippy-content": tooltip });
+ }
+ }
+ }
}
});
}
+ addLeftAnchor(location, attributes = {}) {
+ const widget = document.createElement("span");
+ widget.className = "match-left";
+ widget.style.height = `${this.textHeight * 1.5}px`;
+ widget.style.width = "1px";
+ widget.style.zIndex = "10";
+
+ for (const [key, value] of Object.entries(attributes)) {
+ widget.setAttribute(key, value);
+ }
+
+ this.editor.addWidget(location.startPos, widget);
+
+ const coords = this.editor.charCoords(location.startPos, "local");
+ widget.style.left = `${coords.left}px`;
+ widget.style.top = `${coords.top + 2}px`;
+
+ this.widgets.push(widget);
+ }
+
+ addRightAnchor(location, attributes = {}) {
+ const widget = document.createElement("span");
+ widget.className = "match-right";
+ widget.style.height = `${this.textHeight * 1.5}px`;
+ widget.style.width = "1px";
+ widget.style.zIndex = "10";
+
+ for (const [key, value] of Object.entries(attributes)) {
+ widget.setAttribute(key, value);
+ }
+
+ this.editor.addWidget(location.endPos, widget);
+
+ const coords = this.editor.charCoords(location.startPos, "local");
+ widget.style.left = `${coords.left}px`;
+ widget.style.top = `${coords.top + 2}px`;
+
+ this.widgets.push(widget);
+ }
+
clear() {
this.editor.operation(() => {
let marks = this.activeMarks;
@@ -61,6 +137,11 @@ export default class TestHighlighter extends EventDispatcher {
marks[i].clear();
}
marks.length = 0;
+
+ for (const widget of this.widgets) {
+ widget.parentNode.removeChild(widget);
+ }
+ this.widgets.length = 0;
});
}
}