Skip to content

Commit e5a196f

Browse files
Show empty string match
1 parent fc9b421 commit e5a196f

File tree

2 files changed

+108
-17
lines changed

2 files changed

+108
-17
lines changed

Public/css/highlight.css

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,13 +84,23 @@
8484
.exp-special {
8585
color: #c0c;
8686
}
87-
span.match {
87+
88+
span.match-char {
8889
background: rgba(112, 176, 224, 0.5);
8990
color: #101112;
9091
border-right: solid 1px #ffffff;
9192
border-left: solid 1px #ffffff;
9293
margin-right: -2px;
9394
}
95+
span.match-left {
96+
border-left: solid 2px rgba(255, 0, 0, 0.2);
97+
margin-left: -2px;
98+
}
99+
span.match-right {
100+
border-right: solid 2px rgba(255, 0, 0, 0.2);
101+
margin-right: -2px;
102+
}
103+
94104
span.error {
95105
color: #d22;
96106
font-weight: 700;

Public/js/views/test_highlighter.js

Lines changed: 97 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,12 @@ import Utils from "../misc/utils";
77
export default class TestHighlighter extends EventDispatcher {
88
constructor(editor) {
99
super();
10+
1011
this.editor = editor;
1112
this.activeMarks = [];
13+
this.widgets = [];
14+
15+
this.textHeight = editor.defaultTextHeight();
1216
}
1317

1418
draw(tokens) {
@@ -20,13 +24,6 @@ export default class TestHighlighter extends EventDispatcher {
2024
const marks = this.activeMarks;
2125

2226
for (const token of tokens) {
23-
const className = "match";
24-
const location = Editor.calcRangePos(
25-
this.editor,
26-
token.location.start,
27-
token.location.end - token.location.start
28-
);
29-
3027
const match = Utils.htmlSafe(token.value);
3128
let tooltip = `<div class="text-start font-monospace">
3229
<div><span class="fw-bolder">match:</span> ${match}</div>
@@ -38,29 +35,113 @@ export default class TestHighlighter extends EventDispatcher {
3835
for (const [i, capture] of token.captures.entries()) {
3936
const value = Utils.htmlSafe(capture.value || "");
4037
tooltip += `<div class="text-start font-monospace">
41-
<div><span class="fw-bolder">group #${i + 1}:</span> ${value}</div>
38+
<div><span class="fw-bolder">group #${i + 1}:</span> ${
39+
value === "" ? "empty string" : value
40+
}</div>
4241
</div>`;
4342
}
4443
}
45-
marks.push(
46-
doc.markText(location.startPos, location.endPos, {
47-
className: className,
48-
attributes: {
49-
"data-tippy-content": tooltip,
50-
},
51-
})
52-
);
44+
45+
if (token.location.start < token.location.end) {
46+
const location = Editor.calcRangePos(
47+
editor,
48+
token.location.start,
49+
token.location.end - token.location.start
50+
);
51+
marks.push(
52+
doc.markText(location.startPos, location.endPos, {
53+
className: "match-char",
54+
attributes: {
55+
"data-tippy-content": tooltip,
56+
},
57+
})
58+
);
59+
} else {
60+
const location = Editor.calcRangePos(editor, token.location.start, 1);
61+
62+
if (
63+
location.startPos.line === location.endPos.line &&
64+
location.startPos.ch === location.endPos.ch
65+
) {
66+
this.addLeftAnchor(location, { "data-tippy-content": tooltip });
67+
}
68+
if (location.startPos.line === location.endPos.line) {
69+
if (location.startPos.ch < location.endPos.ch) {
70+
marks.push(
71+
doc.markText(location.startPos, location.endPos, {
72+
className: "match-left",
73+
attributes: {
74+
"data-tippy-content": tooltip,
75+
},
76+
})
77+
);
78+
} else {
79+
// this.addRightAnchor(location, { "data-tippy-content": tooltip });
80+
}
81+
} else {
82+
if (location.startPos.ch === 0 && location.endPos.ch === 0) {
83+
this.addLeftAnchor(location, { "data-tippy-content": tooltip });
84+
} else {
85+
this.addRightAnchor(location, { "data-tippy-content": tooltip });
86+
}
87+
}
88+
}
5389
}
5490
});
5591
}
5692

93+
addLeftAnchor(location, attributes = {}) {
94+
const widget = document.createElement("span");
95+
widget.className = "match-left";
96+
widget.style.height = `${this.textHeight * 1.5}px`;
97+
widget.style.width = "1px";
98+
widget.style.zIndex = "10";
99+
100+
for (const [key, value] of Object.entries(attributes)) {
101+
widget.setAttribute(key, value);
102+
}
103+
104+
this.editor.addWidget(location.startPos, widget);
105+
106+
const coords = this.editor.charCoords(location.startPos, "local");
107+
widget.style.left = `${coords.left}px`;
108+
widget.style.top = `${coords.top + 2}px`;
109+
110+
this.widgets.push(widget);
111+
}
112+
113+
addRightAnchor(location, attributes = {}) {
114+
const widget = document.createElement("span");
115+
widget.className = "match-right";
116+
widget.style.height = `${this.textHeight * 1.5}px`;
117+
widget.style.width = "1px";
118+
widget.style.zIndex = "10";
119+
120+
for (const [key, value] of Object.entries(attributes)) {
121+
widget.setAttribute(key, value);
122+
}
123+
124+
this.editor.addWidget(location.endPos, widget);
125+
126+
const coords = this.editor.charCoords(location.startPos, "local");
127+
widget.style.left = `${coords.left}px`;
128+
widget.style.top = `${coords.top + 2}px`;
129+
130+
this.widgets.push(widget);
131+
}
132+
57133
clear() {
58134
this.editor.operation(() => {
59135
let marks = this.activeMarks;
60136
for (var i = 0, l = marks.length; i < l; i++) {
61137
marks[i].clear();
62138
}
63139
marks.length = 0;
140+
141+
for (const widget of this.widgets) {
142+
widget.parentNode.removeChild(widget);
143+
}
144+
this.widgets.length = 0;
64145
});
65146
}
66147
}

0 commit comments

Comments
 (0)