Skip to content

Commit 82eb439

Browse files
authored
feat: Add option to use SVG gutter icons (#5107)
* add option for using SVG icons Adds an option (useSvgGutterIcons) to use SVG gutter icons (only annotation icons for now) to the VirtualRendererOptions.
1 parent 10eab4f commit 82eb439

10 files changed

+93
-8
lines changed

Makefile.dryice.js

+5-1
Original file line numberDiff line numberDiff line change
@@ -606,7 +606,11 @@ function extractCss(callback) {
606606
}
607607
var buffer = Buffer.from(data.slice(i + 1), "base64");
608608
imageCounter++;
609-
var imageName = name + "-" + imageCounter + ".png";
609+
var imageName;
610+
if (/^image\/svg\+xml/.test(data))
611+
imageName = name + "-" + imageCounter + ".svg";
612+
else
613+
imageName = name + "-" + imageCounter + ".png";
610614
images[imageName] = buffer;
611615
console.log("url(\"" + directory + "/" + imageName + "\")");
612616
return "url(\"" + directory + "/" + imageName + "\")";

ace.d.ts

+1
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,7 @@ export namespace Ace {
194194
theme: string;
195195
hasCssTransforms: boolean;
196196
maxPixelHeight: number;
197+
useSvgGutterIcons: boolean;
197198
}
198199

199200
export interface MouseHandlerOptions {

src/css/editor.css.js

+29-2
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ module.exports = `
105105
pointer-events: none;
106106
}
107107
108-
.ace_gutter-cell {
108+
.ace_gutter-cell, .ace_gutter-cell_svg-icons {
109109
position: absolute;
110110
top: 0;
111111
left: 0;
@@ -115,6 +115,11 @@ module.exports = `
115115
background-repeat: no-repeat;
116116
}
117117
118+
.ace_gutter-cell_svg-icons .ace_icon_svg{
119+
margin-left: -14px;
120+
float: left;
121+
}
122+
118123
.ace_gutter-cell.ace_error, .ace_icon.ace_error {
119124
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAABOFBMVEX/////////QRswFAb/Ui4wFAYwFAYwFAaWGAfDRymzOSH/PxswFAb/SiUwFAYwFAbUPRvjQiDllog5HhHdRybsTi3/Tyv9Tir+Syj/UC3////XurebMBIwFAb/RSHbPx/gUzfdwL3kzMivKBAwFAbbvbnhPx66NhowFAYwFAaZJg8wFAaxKBDZurf/RB6mMxb/SCMwFAYwFAbxQB3+RB4wFAb/Qhy4Oh+4QifbNRcwFAYwFAYwFAb/QRzdNhgwFAYwFAbav7v/Uy7oaE68MBK5LxLewr/r2NXewLswFAaxJw4wFAbkPRy2PyYwFAaxKhLm1tMwFAazPiQwFAaUGAb/QBrfOx3bvrv/VC/maE4wFAbRPBq6MRO8Qynew8Dp2tjfwb0wFAbx6eju5+by6uns4uH9/f36+vr/GkHjAAAAYnRSTlMAGt+64rnWu/bo8eAA4InH3+DwoN7j4eLi4xP99Nfg4+b+/u9B/eDs1MD1mO7+4PHg2MXa347g7vDizMLN4eG+Pv7i5evs/v79yu7S3/DV7/498Yv24eH+4ufQ3Ozu/v7+y13sRqwAAADLSURBVHjaZc/XDsFgGIBhtDrshlitmk2IrbHFqL2pvXf/+78DPokj7+Fz9qpU/9UXJIlhmPaTaQ6QPaz0mm+5gwkgovcV6GZzd5JtCQwgsxoHOvJO15kleRLAnMgHFIESUEPmawB9ngmelTtipwwfASilxOLyiV5UVUyVAfbG0cCPHig+GBkzAENHS0AstVF6bacZIOzgLmxsHbt2OecNgJC83JERmePUYq8ARGkJx6XtFsdddBQgZE2nPR6CICZhawjA4Fb/chv+399kfR+MMMDGOQAAAABJRU5ErkJggg==");
120125
background-repeat: no-repeat;
@@ -136,6 +141,19 @@ module.exports = `
136141
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQBAMAAADt3eJSAAAAJFBMVEUAAAChoaGAgIAqKiq+vr6tra1ZWVmUlJSbm5s8PDxubm56enrdgzg3AAAAAXRSTlMAQObYZgAAAClJREFUeNpjYMAPdsMYHegyJZFQBlsUlMFVCWUYKkAZMxZAGdxlDMQBAG+TBP4B6RyJAAAAAElFTkSuQmCC");
137142
}
138143
144+
.ace_icon_svg.ace_error {
145+
-webkit-mask-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNiAxNiI+CjxnIHN0cm9rZS13aWR0aD0iMiIgc3Ryb2tlPSJyZWQiIHNoYXBlLXJlbmRlcmluZz0iZ2VvbWV0cmljUHJlY2lzaW9uIj4KPGNpcmNsZSBmaWxsPSJub25lIiBjeD0iOCIgY3k9IjgiIHI9IjciIHN0cm9rZS1saW5lam9pbj0icm91bmQiLz4KPGxpbmUgeDE9IjExIiB5MT0iNSIgeDI9IjUiIHkyPSIxMSIvPgo8bGluZSB4MT0iMTEiIHkxPSIxMSIgeDI9IjUiIHkyPSI1Ii8+CjwvZz4KPC9zdmc+");
146+
background-color: crimson;
147+
}
148+
.ace_icon_svg.ace_warning {
149+
-webkit-mask-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNiAxNiI+CjxnIHN0cm9rZS13aWR0aD0iMiIgc3Ryb2tlPSJkYXJrb3JhbmdlIiBzaGFwZS1yZW5kZXJpbmc9Imdlb21ldHJpY1ByZWNpc2lvbiI+Cjxwb2x5Z29uIHN0cm9rZS1saW5lam9pbj0icm91bmQiIGZpbGw9Im5vbmUiIHBvaW50cz0iOCAxIDE1IDE1IDEgMTUgOCAxIi8+CjxyZWN0IHg9IjgiIHk9IjEyIiB3aWR0aD0iMC4wMSIgaGVpZ2h0PSIwLjAxIi8+CjxsaW5lIHgxPSI4IiB5MT0iNiIgeDI9IjgiIHkyPSIxMCIvPgo8L2c+Cjwvc3ZnPg==");
150+
background-color: darkorange;
151+
}
152+
.ace_icon_svg.ace_info {
153+
-webkit-mask-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNiAxNiI+CjxnIHN0cm9rZS13aWR0aD0iMiIgc3Ryb2tlPSJibHVlIiBzaGFwZS1yZW5kZXJpbmc9Imdlb21ldHJpY1ByZWNpc2lvbiI+CjxjaXJjbGUgZmlsbD0ibm9uZSIgY3g9IjgiIGN5PSI4IiByPSI3IiBzdHJva2UtbGluZWpvaW49InJvdW5kIi8+Cjxwb2x5bGluZSBwb2ludHM9IjggMTEgOCA4Ii8+Cjxwb2x5bGluZSBwb2ludHM9IjkgOCA2IDgiLz4KPGxpbmUgeDE9IjEwIiB5MT0iMTEiIHgyPSI2IiB5Mj0iMTEiLz4KPHJlY3QgeD0iOCIgeT0iNSIgd2lkdGg9IjAuMDEiIGhlaWdodD0iMC4wMSIvPgo8L2c+Cjwvc3ZnPg==");
154+
background-color: royalblue;
155+
}
156+
139157
.ace_scrollbar {
140158
contain: strict;
141159
position: absolute;
@@ -437,7 +455,16 @@ module.exports = `
437455
width: 18px;
438456
}
439457
440-
.ace_folding-enabled > .ace_gutter-cell {
458+
.ace_icon_svg {
459+
display: inline-block;
460+
width: 12px;
461+
vertical-align: top;
462+
-webkit-mask-repeat: no-repeat;
463+
-webkit-mask-size: 12px;
464+
-webkit-mask-position: center;
465+
}
466+
467+
.ace_folding-enabled > .ace_gutter-cell, .ace_folding-enabled > .ace_gutter-cell_svg-icons {
441468
padding-right: 13px;
442469
}
443470

src/editor.js

+1
Original file line numberDiff line numberDiff line change
@@ -2883,6 +2883,7 @@ config.defineOptions(Editor.prototype, "editor", {
28832883
maxPixelHeight: "renderer",
28842884
useTextareaForIME: "renderer",
28852885
useResizeObserver: "renderer",
2886+
useSvgGutterIcons: "renderer",
28862887

28872888
scrollSpeed: "$mouseHandler",
28882889
dragDelay: "$mouseHandler",

src/ext/options.js

+3
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,9 @@ var optionGroups = {
194194
},
195195
"Custom scrollbar": {
196196
path: "customScrollbar"
197+
},
198+
"Use SVG gutter icons": {
199+
path: "useSvgGutterIcons"
197200
}
198201
}
199202
};

src/layer/gutter.js

+26-3
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,7 @@ class Gutter{
278278

279279
var textNode = element.childNodes[0];
280280
var foldWidget = element.childNodes[1];
281+
var annotationNode = element.childNodes[2];
281282

282283
var firstLineNumber = session.$firstLineNumber;
283284

@@ -287,7 +288,27 @@ class Gutter{
287288
var foldWidgets = this.$showFoldWidgets && session.foldWidgets;
288289
var foldStart = fold ? fold.start.row : Number.MAX_VALUE;
289290

290-
var className = "ace_gutter-cell ";
291+
var lineHeight = config.lineHeight + "px";
292+
293+
var className;
294+
if (this.$useSvgGutterIcons){
295+
className = "ace_gutter-cell_svg-icons ";
296+
297+
if (this.$annotations[row]){
298+
annotationNode.className = "ace_icon_svg" + this.$annotations[row].className;
299+
300+
dom.setStyle(annotationNode.style, "height", lineHeight);
301+
dom.setStyle(annotationNode.style, "display", "block");
302+
}
303+
else {
304+
dom.setStyle(annotationNode.style, "display", "none");
305+
}
306+
}
307+
else {
308+
className = "ace_gutter-cell ";
309+
dom.setStyle(annotationNode.style, "display", "none");
310+
}
311+
291312
if (this.$highlightGutterLine) {
292313
if (row == this.$cursorRow || (fold && row < this.$cursorRow && row >= foldStart && this.$cursorRow <= fold.end.row)) {
293314
className += "ace_gutter-active-line ";
@@ -324,8 +345,7 @@ class Gutter{
324345
if (foldWidget.className != className)
325346
foldWidget.className = className;
326347

327-
var foldHeight = config.lineHeight + "px";
328-
dom.setStyle(foldWidget.style, "height", foldHeight);
348+
dom.setStyle(foldWidget.style, "height", lineHeight);
329349
dom.setStyle(foldWidget.style, "display", "inline-block");
330350
} else {
331351
if (foldWidget) {
@@ -415,6 +435,9 @@ function onCreateCell(element) {
415435

416436
var foldWidget = dom.createElement("span");
417437
element.appendChild(foldWidget);
438+
439+
var annotationNode = dom.createElement("span");
440+
element.appendChild(annotationNode);
418441

419442
return element;
420443
}

src/mouse/default_gutter_handler.js

+3-1
Original file line numberDiff line numberDiff line change
@@ -57,9 +57,11 @@ function GutterHandler(mouseHandler) {
5757
info: {singular: "information message", plural: "information messages"}
5858
};
5959

60+
var iconClassName = gutter.$useSvgGutterIcons ? "ace_icon_svg" : "ace_icon";
61+
6062
// Construct the body of the tooltip.
6163
for (var i = 0; i < annotation.text.length; i++) {
62-
var line = `<span class='ace_${annotation.type[i]} ace_icon' aria-label='${annotationLabels[annotation.type[i]].singular}' role=img> </span> ${annotation.text[i]}`;
64+
var line = `<span class='ace_${annotation.type[i]} ${iconClassName}' aria-label='${annotationLabels[annotation.type[i]].singular}' role=img> </span> ${annotation.text[i]}`;
6365
annotationMessages[annotation.type[i]].push(line);
6466
}
6567
var tooltipBody = "<div class='ace_gutter-tooltip_body'>";

src/mouse/default_gutter_handler_test.js

+18
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,24 @@ module.exports = {
112112
assert.ok(/info test/.test(tooltipBody.textContent));
113113
}, 100);
114114
},
115+
"test: gutter svg icons" : function() {
116+
var editor = this.editor;
117+
var value = "";
118+
119+
editor.session.setMode(new Mode());
120+
editor.setOption("useSvgGutterIcons", true);
121+
editor.setValue(value, -1);
122+
editor.session.setAnnotations([{row: 0, column: 0, type: "error", text: "error test"}]);
123+
editor.renderer.$loop._flush();
124+
125+
var lines = editor.renderer.$gutterLayer.$lines;
126+
var line = lines.cells[0].element;
127+
assert.ok(/ace_gutter-cell_svg-icons/.test(line.className));
128+
129+
var annotation = line.children[2];
130+
assert.ok(/ace_icon_svg/.test(annotation.className));
131+
},
132+
115133

116134
tearDown : function() {
117135
this.editor.destroy();

src/mouse/mouse_handler_test.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ module.exports = {
126126
editor.setValue(value, -1);
127127
editor.renderer.$loop._flush();
128128
var lines = editor.renderer.$gutterLayer.$lines;
129-
var toggler = lines.cells[0].element.lastChild;
129+
var toggler = lines.cells[0].element.children[1];
130130
var rect = toggler.getBoundingClientRect();
131131
if (!rect.left) rect.left = 100; // for mockdom
132132
toggler.dispatchEvent(MouseEvent("down", {x: rect.left, y: rect.top}));

src/virtual_renderer.js

+6
Original file line numberDiff line numberDiff line change
@@ -1902,6 +1902,12 @@ config.defineOptions(VirtualRenderer.prototype, "renderer", {
19021902
},
19031903
initialValue: true
19041904
},
1905+
useSvgGutterIcons: {
1906+
set: function(value){
1907+
this.$gutterLayer.$useSvgGutterIcons = value;
1908+
},
1909+
initialValue: false
1910+
},
19051911
fadeFoldWidgets: {
19061912
set: function(show) {
19071913
dom.setCssClass(this.$gutter, "ace_fade-fold-widgets", show);

0 commit comments

Comments
 (0)