Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/css/editor-css.js
Original file line number Diff line number Diff line change
Expand Up @@ -705,4 +705,8 @@ module.exports = `

.ace_hidden_token {
display: none;
}

.ace_invisible_hidden {
color: transparent !important;
}`;
53 changes: 34 additions & 19 deletions src/ext/whitespaces_in_selection.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@ var dom = require("../lib/dom");

dom.importCssString(`
.ace_whitespaces_in_selection {
color: rgba(0,0,0,0.29);
color: rgba(0,0,0,0.29) !important;
}

.ace_dark .ace_whitespaces_in_selection {
color: rgba(187, 181, 181, 0.5);
color: rgba(187, 181, 181, 0.5) !important;
}
`, "ace_whitespaces_in_selection", false);

Expand All @@ -33,15 +33,14 @@ config.defineOptions(Editor.prototype, "editor", {
this.$boundChangeSelectionForWhitespace = $onChangeSelectionForWhitespace.bind(this);
}
this.on("changeSelection", this.$boundChangeSelectionForWhitespace);
$setRenderWhitespaceMarkers(this, true);
} else {
this.off("changeSelection", this.$boundChangeSelectionForWhitespace);

if (this.session && this.session.$invisibleMarkerId) {
this.session.removeTextMarker(this.session.$invisibleMarkerId);
this.session.$invisibleMarkerId = null;
}
$removeWhitespaceMarkers(this.session);

this.$boundChangeSelectionForWhitespace = null;
$setRenderWhitespaceMarkers(this, false);
}
},
get: function() {
Expand All @@ -51,19 +50,35 @@ config.defineOptions(Editor.prototype, "editor", {
}
});

function $onChangeSelectionForWhitespace() {
let invisibleMarkerId = this.session.$invisibleMarkerId;
if (invisibleMarkerId) {
this.session.removeTextMarker(invisibleMarkerId);
this.session.$invisibleMarkerId = null;
function $setRenderWhitespaceMarkers(editor, render) {
var textLayer = editor.renderer && editor.renderer.$textLayer;
if (!textLayer || typeof textLayer.setRenderWhitespaceMarkers !== "function")
return;

textLayer.setRenderWhitespaceMarkers(render);
editor.renderer.updateText();
}

function $removeWhitespaceMarkers(session) {
if (!session) return;

var invisibleMarkerIds = session.$invisibleMarkerIds || [];
for (var i = 0; i < invisibleMarkerIds.length; i++) {
session.removeTextMarker(invisibleMarkerIds[i]);
}
session.$invisibleMarkerIds = [];
}

function $onChangeSelectionForWhitespace() {
$removeWhitespaceMarkers(this.session);

var currentRange = this.selection.getRange();
if (!currentRange.isEmpty()) {
this.session.$invisibleMarkerId = this.session.addTextMarker(
currentRange,
"ace_whitespaces_in_selection",
"invisible"
);
var ranges = typeof this.selection.getAllRanges === "function" ? this.selection.getAllRanges()
: [this.selection.getRange()];

for (var j = 0; j < ranges.length; j++) {
if (!ranges[j].isEmpty()) {
this.session.$invisibleMarkerIds.push(
this.session.addTextMarker(ranges[j], "ace_whitespaces_in_selection", "invisible"));
}
}
}
}
56 changes: 52 additions & 4 deletions src/ext/whitespaces_in_selection_test.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
"use strict";

require("../test/mockdom");
require("../multi_select");
var assert = require("assert");
var EditSession = require("../edit_session").EditSession;
var Editor = require("../editor").Editor;
var Range = require("../range").Range;
var MockRenderer = require("../test/mockrenderer").MockRenderer;
require("./whitespaces_in_selection");

Expand All @@ -25,28 +27,74 @@ module.exports = {
assert.ok(this.editor.$boundChangeSelectionForWhitespace);
},

"test: toggling extension updates whitespace marker rendering": function() {
var renderValues = [];
var updateCount = 0;
this.editor.renderer.$textLayer = {
setRenderWhitespaceMarkers: function(render) {
renderValues.push(render);
}
};
this.editor.renderer.updateText = function() {
updateCount++;
};

this.editor.setOption("showWhitespacesInSelection", true);
this.editor.setOption("showWhitespacesInSelection", false);

assert.deepEqual(renderValues, [true, false]);
assert.equal(updateCount, 2);
},

"test: turning off extension": function() {
this.editor.setOption("showWhitespacesInSelection", true);
assert.equal(this.editor.getOption("showWhitespacesInSelection"), true);
this.editor.selection.setRange({start: {row: 0, column: 0}, end: {row: 0, column: 5}});
this.editor.selection.addRange(new Range(1, 4, 1, 8));

var markerIds = this.session.$invisibleMarkerIds.slice();
assert.equal(markerIds.length, 2);
markerIds.forEach(function(markerId) {
assert.ok(this.session.getTextMarkers()[markerId]);
}, this);

this.editor.setOption("showWhitespacesInSelection", false);
assert.equal(this.editor.getOption("showWhitespacesInSelection"), false);

assert.equal(this.editor.$boundChangeSelectionForWhitespace, null);
assert.deepEqual(this.session.$invisibleMarkerIds, []);
markerIds.forEach(function(markerId) {
assert.ok(!this.session.getTextMarkers()[markerId]);
}, this);
},

"test: marker present after selection": function() {
this.editor.setOption("showWhitespacesInSelection", true);

this.editor.selection.setRange({start: {row: 0, column: 0}, end: {row: 0, column: 5}});

assert.ok(this.session.$invisibleMarkerId);
assert.equal(this.session.$invisibleMarkerIds.length, 1);

var markers = this.session.getTextMarkers();
var marker = markers[this.session.$invisibleMarkerIds[0]];
assert.ok(marker);
assert.equal(marker.className, "ace_whitespaces_in_selection");
},

"test: markers present after multiple selections": function() {
this.editor.setOption("showWhitespacesInSelection", true);

this.editor.selection.setRange(new Range(0, 0, 0, 5));
this.editor.selection.addRange(new Range(1, 4, 1, 8));

assert.equal(this.session.$invisibleMarkerIds.length, 2);

var markers = this.session.getTextMarkers();
assert.ok(markers[this.session.$invisibleMarkerId]);
assert.equal(markers[this.session.$invisibleMarkerId].className, "ace_whitespaces_in_selection");
this.session.$invisibleMarkerIds.forEach(function(markerId) {
assert.ok(markers[markerId]);
assert.equal(markers[markerId].className, "ace_whitespaces_in_selection");
});
}
};

require("../test/run")(module);
require("../test/run")(module);
39 changes: 25 additions & 14 deletions src/layer/text.js
Original file line number Diff line number Diff line change
Expand Up @@ -132,11 +132,15 @@ class Text {
$computeTabString() {
var tabSize = this.session.getTabSize();
this.tabSize = tabSize;
var renderTabGlyphs = this.showTabs || this.$renderWhitespaceMarkers;
var renderSpaceGlyphs = this.showSpaces || this.$renderWhitespaceMarkers;
/**@type{any}*/var tabStr = this.$tabStrings = [0];
for (var i = 1; i < tabSize + 1; i++) {
if (this.showTabs) {
if (renderTabGlyphs) {
var span = this.dom.createElement("span");
span.className = "ace_invisible ace_invisible_tab";
if (!this.showTabs)
span.className += " ace_invisible_hidden";
span.textContent = lang.stringRepeat(this.TAB_CHAR, i);
tabStr.push(span);
} else {
Expand All @@ -146,13 +150,17 @@ class Text {
if (this.displayIndentGuides) {
this.$indentGuideRe = /\s\S| \t|\t |\s$/;
var className = "ace_indent-guide";
var spaceClass = this.showSpaces ? " ace_invisible ace_invisible_space" : "";
var spaceContent = this.showSpaces
var spaceClass = renderSpaceGlyphs ? " ace_invisible ace_invisible_space" : "";
if (renderSpaceGlyphs && !this.showSpaces)
spaceClass += " ace_invisible_hidden";
var spaceContent = renderSpaceGlyphs
? lang.stringRepeat(this.SPACE_CHAR, this.tabSize)
: lang.stringRepeat(" ", this.tabSize);

var tabClass = this.showTabs ? " ace_invisible ace_invisible_tab" : "";
var tabContent = this.showTabs
var tabClass = renderTabGlyphs ? " ace_invisible ace_invisible_tab" : "";
if (renderTabGlyphs && !this.showTabs)
tabClass += " ace_invisible_hidden";
var tabContent = renderTabGlyphs
? lang.stringRepeat(this.TAB_CHAR, this.tabSize)
: spaceContent;

Expand Down Expand Up @@ -363,7 +371,7 @@ class Text {
var controlCharacter = m[3];
var cjkSpace = m[4];

if (!self.showSpaces && simpleSpace)
if (!self.showSpaces && !self.$renderWhitespaceMarkers && simpleSpace)
continue;

var before = i != m.index ? value.slice(i, m.index) : "";
Expand All @@ -381,9 +389,11 @@ class Text {
valueFragment.appendChild(text);
screenColumn += tabSize - 1;
} else if (simpleSpace) {
if (self.showSpaces) {
if (self.showSpaces || self.$renderWhitespaceMarkers) {
var span = this.dom.createElement("span");
span.className = "ace_invisible ace_invisible_space";
if (!self.showSpaces)
span.className += " ace_invisible_hidden";
span.textContent = lang.stringRepeat(self.SPACE_CHAR, simpleSpace.length);
valueFragment.appendChild(span);
} else {
Expand All @@ -395,9 +405,11 @@ class Text {
span.textContent = lang.stringRepeat(self.SPACE_CHAR, controlCharacter.length);
valueFragment.appendChild(span);
} else if (cjkSpace) {
if (self.showSpaces) {
if (self.showSpaces || self.$renderWhitespaceMarkers) {
var span = this.dom.createElement("span");
span.className = "ace_invisible ace_invisible_space";
if (!self.showSpaces)
span.className += " ace_invisible_hidden";
span.textContent = lang.stringRepeat(self.CJK_SPACE_CHAR, cjkSpace.length);
valueFragment.appendChild(span);
} else {
Expand Down Expand Up @@ -533,12 +545,10 @@ class Text {
return;
}
}
var childNodes = element.childNodes;
if (childNodes) {
let node = childNodes[indentLevel - 1];
if (node && node.classList && node.classList.contains("ace_indent-guide")) node.classList.add(
"ace_indent-guide-active");
}
var indentGuides = element.querySelectorAll(".ace_indent-guide");
var node = indentGuides[indentLevel - 1];
if (node)
node.classList.add("ace_indent-guide-active");
}
}

Expand Down Expand Up @@ -792,6 +802,7 @@ Text.prototype.showInvisibles = false;
Text.prototype.showSpaces = false;
Text.prototype.showTabs = false;
Text.prototype.showEOL = false;
Text.prototype.$renderWhitespaceMarkers = false;
Text.prototype.displayIndentGuides = true;
Text.prototype.$highlightIndentGuides = true;
Text.prototype.$tabStrings = [];
Expand Down
Loading
Loading