highlight matching brackets
This commit is contained in:
parent
09c873c780
commit
2e906f4a35
4 changed files with 166 additions and 0 deletions
|
|
@ -92,4 +92,10 @@
|
||||||
.marker-layer .selection {
|
.marker-layer .selection {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
background: rgba(77, 151, 255, 0.33);
|
background: rgba(77, 151, 255, 0.33);
|
||||||
|
}
|
||||||
|
|
||||||
|
.marker-layer .bracket {
|
||||||
|
position: absolute;
|
||||||
|
margin: -1px 0 0 -1px;
|
||||||
|
border: 1px solid rgb(192, 192, 192);
|
||||||
}
|
}
|
||||||
|
|
@ -46,8 +46,41 @@ ace.Editor.prototype.resize = function() {
|
||||||
|
|
||||||
ace.Editor.prototype.updateCursor = function() {
|
ace.Editor.prototype.updateCursor = function() {
|
||||||
this.renderer.updateCursor(this.cursor);
|
this.renderer.updateCursor(this.cursor);
|
||||||
|
this._highlightBrackets();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
ace.Editor.prototype._highlightBrackets = function() {
|
||||||
|
|
||||||
|
if (this._bracketHighlight) {
|
||||||
|
this.renderer.removeMarker(this._bracketHighlight);
|
||||||
|
this._bracketHighlight = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this._highlightPending) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// perform highlight async to not block the browser during navigation
|
||||||
|
var self = this;
|
||||||
|
this._highlightPending = true;
|
||||||
|
setTimeout(function() {
|
||||||
|
self._highlightPending = false;
|
||||||
|
|
||||||
|
var pos = self.doc.findMatchingBracket(self.cursor);
|
||||||
|
if (pos) {
|
||||||
|
range = {
|
||||||
|
start: pos,
|
||||||
|
end: {
|
||||||
|
row: pos.row,
|
||||||
|
column: pos.column+1
|
||||||
|
}
|
||||||
|
};
|
||||||
|
self._bracketHighlight = self.renderer.addMarker(range, "bracket");
|
||||||
|
}
|
||||||
|
}, 10);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
ace.Editor.prototype.onFocus = function() {
|
ace.Editor.prototype.onFocus = function() {
|
||||||
this.renderer.showCursor();
|
this.renderer.showCursor();
|
||||||
this.renderer.visualizeFocus();
|
this.renderer.visualizeFocus();
|
||||||
|
|
|
||||||
|
|
@ -90,6 +90,98 @@ ace.TextDocument.prototype.getTextRange = function(range) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
ace.TextDocument.prototype.findMatchingBracket = function(position) {
|
||||||
|
if (position.column == 0) return null;
|
||||||
|
|
||||||
|
var charBeforeCursor = this.getLine(position.row).charAt(position.column-1);
|
||||||
|
if (charBeforeCursor == "") return null;
|
||||||
|
|
||||||
|
var match = charBeforeCursor.match(/([\(\[\{])|([\)\]\}])/);
|
||||||
|
if (!match) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (match[1]) {
|
||||||
|
return this._findClosingBracket(match[1], position);
|
||||||
|
} else {
|
||||||
|
return this._findOpeningBracket(match[2], position);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ace.TextDocument.prototype._brackets = {
|
||||||
|
")": "(",
|
||||||
|
"(": ")",
|
||||||
|
"]": "[",
|
||||||
|
"[": "]",
|
||||||
|
"{": "}",
|
||||||
|
"}": "{"
|
||||||
|
};
|
||||||
|
|
||||||
|
ace.TextDocument.prototype._findOpeningBracket = function(bracket, position) {
|
||||||
|
var openBracket = this._brackets[bracket];
|
||||||
|
|
||||||
|
var column = position.column - 2;
|
||||||
|
var row = position.row;
|
||||||
|
var depth = 1;
|
||||||
|
|
||||||
|
var line = this.getLine(row);
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
while(column >= 0) {
|
||||||
|
var char = line.charAt(column);
|
||||||
|
if (char == openBracket) {
|
||||||
|
depth -= 1;
|
||||||
|
if (depth == 0) {
|
||||||
|
return {row: row, column: column};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (char == bracket) {
|
||||||
|
depth +=1;
|
||||||
|
}
|
||||||
|
column -= 1;
|
||||||
|
}
|
||||||
|
row -=1;
|
||||||
|
if (row < 0) break;
|
||||||
|
|
||||||
|
var line = this.getLine(row);
|
||||||
|
var column = line.length-1;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
ace.TextDocument.prototype._findClosingBracket = function(bracket, position) {
|
||||||
|
var closingBracket = this._brackets[bracket];
|
||||||
|
|
||||||
|
var column = position.column;
|
||||||
|
var row = position.row;
|
||||||
|
var depth = 1;
|
||||||
|
|
||||||
|
var line = this.getLine(row);
|
||||||
|
var lineCount = this.getLength();
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
while(column < line.length) {
|
||||||
|
var char = line.charAt(column);
|
||||||
|
if (char == closingBracket) {
|
||||||
|
depth -= 1;
|
||||||
|
if (depth == 0) {
|
||||||
|
return {row: row, column: column};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (char == bracket) {
|
||||||
|
depth +=1;
|
||||||
|
}
|
||||||
|
column += 1;
|
||||||
|
}
|
||||||
|
row +=1;
|
||||||
|
if (row >= lineCount) break;
|
||||||
|
|
||||||
|
var line = this.getLine(row);
|
||||||
|
var column = 0;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
ace.TextDocument.prototype.insert = function(position, text) {
|
ace.TextDocument.prototype.insert = function(position, text) {
|
||||||
var end = this._insert(position, text);
|
var end = this._insert(position, text);
|
||||||
this.fireChangeEvent(position.row, position.row == end.row ? position.row
|
this.fireChangeEvent(position.row, position.row == end.row ? position.row
|
||||||
|
|
|
||||||
35
test/TextDocumentTest.js
Normal file
35
test/TextDocumentTest.js
Normal file
|
|
@ -0,0 +1,35 @@
|
||||||
|
var TextDocumentTest = new TestCase("TextDocumentTest", {
|
||||||
|
|
||||||
|
"test: find matching opening bracket" : function() {
|
||||||
|
var doc = new ace.TextDocument(["(()(", "())))"].join("\n"));
|
||||||
|
|
||||||
|
assertPosition(0, 1, doc.findMatchingBracket({row: 0, column: 3}));
|
||||||
|
assertPosition(1, 0, doc.findMatchingBracket({row: 1, column: 2}));
|
||||||
|
assertPosition(0, 3, doc.findMatchingBracket({row: 1, column: 3}));
|
||||||
|
assertPosition(0, 0, doc.findMatchingBracket({row: 1, column: 4}));
|
||||||
|
assertEquals(null, doc.findMatchingBracket({row: 1, column: 5}));
|
||||||
|
},
|
||||||
|
|
||||||
|
"test: find matching closing bracket" : function() {
|
||||||
|
var doc = new ace.TextDocument(["(()(", "())))"].join("\n"));
|
||||||
|
|
||||||
|
assertPosition(1, 1, doc.findMatchingBracket({row: 1, column: 1}));
|
||||||
|
assertPosition(1, 1, doc.findMatchingBracket({row: 1, column: 1}));
|
||||||
|
assertPosition(1, 2, doc.findMatchingBracket({row: 0, column: 4}));
|
||||||
|
assertPosition(0, 2, doc.findMatchingBracket({row: 0, column: 2}));
|
||||||
|
assertPosition(1, 3, doc.findMatchingBracket({row: 0, column: 1}));
|
||||||
|
assertEquals(null, doc.findMatchingBracket({row: 0, column: 0}));
|
||||||
|
},
|
||||||
|
|
||||||
|
"test: match different bracket types" : function() {
|
||||||
|
var doc = new ace.TextDocument(["({[", ")]}"].join("\n"));
|
||||||
|
|
||||||
|
assertPosition(1, 0, doc.findMatchingBracket({row: 0, column: 1}));
|
||||||
|
assertPosition(1, 2, doc.findMatchingBracket({row: 0, column: 2}));
|
||||||
|
assertPosition(1, 1, doc.findMatchingBracket({row: 0, column: 3}));
|
||||||
|
|
||||||
|
assertPosition(0, 0, doc.findMatchingBracket({row: 1, column: 1}));
|
||||||
|
assertPosition(0, 2, doc.findMatchingBracket({row: 1, column: 2}));
|
||||||
|
assertPosition(0, 1, doc.findMatchingBracket({row: 1, column: 3}));
|
||||||
|
}
|
||||||
|
});
|
||||||
Loading…
Add table
Add a link
Reference in a new issue