add html tag support to jumpToMatching

This commit is contained in:
Adam Jimenez 2014-06-09 17:09:31 +01:00
commit d7c7cb1b4d

View file

@ -48,6 +48,7 @@ var EventEmitter = require("./lib/event_emitter").EventEmitter;
var CommandManager = require("./commands/command_manager").CommandManager;
var defaultCommands = require("./commands/default_commands").commands;
var config = require("./config");
var TokenIterator = require("./token_iterator").TokenIterator;
/**
* The main entry point into the Ace functionality.
@ -1915,26 +1916,152 @@ var Editor = function(renderer, session) {
};
/**
* Moves the cursor's row and column to the next matching bracket.
* Moves the cursor's row and column to the next matching bracket or HTML tag.
*
**/
this.jumpToMatching = function(select) {
var cursor = this.getCursorPosition();
var iterator = new TokenIterator(this.session, cursor.row, cursor.column);
var prevToken = iterator.getCurrentToken();
var token;
var range = this.session.getBracketRange(cursor);
if (!range) {
range = this.find({
needle: /[{}()\[\]]/g,
preventScroll:true,
start: {row: cursor.row, column: cursor.column - 1}
});
if (!range)
return;
var pos = range.start;
if (pos.row == cursor.row && Math.abs(pos.column - cursor.column) < 2)
range = this.session.getBracketRange(pos);
//handle bracket as first char on line
if (prevToken && prevToken.index===0)
token = prevToken;
else
token = iterator.stepForward();
if (!token)
return;
//get next closing tag or bracket
var matchType;
var found = false;
var inverse;
var depth = {};
do {
if (token.value.match(/[{}()\[\]]/g)) {
for (var i=0; i<token.value.length; i++) {
switch (token.value[i]) {
case '(':
case '[':
case '{':
if (isNaN(depth[token.value[i]])) {
depth[token.value] = 0;
}
depth[token.value[i]]++;
break;
case ')':
case ']':
case '}':
inverse = this.session.$brackets[token.value[i]];
if (isNaN(depth[inverse])) {
depth[inverse] = 0;
}
depth[inverse]--;
if (depth[inverse]===-1) {
matchType = 'bracket';
found = true;
}
break;
}
}
} else if (token && token.type.indexOf('tag-name') !== -1) {
if (isNaN(depth[token.value])) {
depth[token.value] = 0;
}
if (prevToken.value==='<') {
depth[token.value]++;
} else if ( prevToken.value==='</') {
depth[token.value]--;
}
if (depth[token.value]===-1) {
matchType = 'tag';
found = true;
}
}
if (found===false) {
prevToken = token;
token = iterator.stepForward();
}
} while (token && found===false);
//no match found
if (!matchType) {
return;
}
var range;
if (matchType==='bracket') {
range = this.session.getBracketRange(cursor);
if (!range) {
range = new Range(
iterator.getCurrentTokenRow(),
iterator.getCurrentTokenColumn(),
iterator.getCurrentTokenRow(),
iterator.getCurrentTokenColumn()
);
if (!range)
return;
var pos = range.start;
if (pos.row === cursor.row && Math.abs(pos.column - cursor.column) < 2)
range = this.session.getBracketRange(pos);
}
} else if(matchType==='tag') {
if (token && token.type.indexOf('tag-name') !== -1)
var tag = token.value;
else
return;
var range = new Range(
iterator.getCurrentTokenRow(),
iterator.getCurrentTokenColumn()-2,
iterator.getCurrentTokenRow(),
iterator.getCurrentTokenColumn()-2
);
//find matching tag
if (range.compare(cursor.row, cursor.column)===0) {
found = false;
do {
token = prevToken;
prevToken = iterator.stepBackward();
if (prevToken) {
if (prevToken.type.indexOf('tag-close') !== -1) {
range.setEnd(iterator.getCurrentTokenRow(), iterator.getCurrentTokenColumn()+1);
}
if (token.value===tag && token.type.indexOf('tag-name') !== -1) {
if (prevToken.value==='<') {
depth[tag]++;
} else if ( prevToken.value==='</') {
depth[tag]--;
}
if (depth[tag]===0)
found = true;
}
}
} while (prevToken && found===false);
}
//we found it
if (token && token.type.indexOf('tag-name')) {
var pos = range.start;
if (pos.row == cursor.row && Math.abs(pos.column - cursor.column) < 2)
pos = range.end;
}
}
pos = range && range.cursor || pos;
if (pos) {
if (select) {