From 9a4a387de65d035a49f1398befc3c8541d1c02c3 Mon Sep 17 00:00:00 2001 From: Adam Jimenez Date: Fri, 6 Jun 2014 10:32:18 +0100 Subject: [PATCH] Jump To Matching Tag Alt-P: Jump to Matching Tag Alt-Shift-P: Select to Matching Tag fixes #1158 --- lib/ace/commands/default_commands.js | 12 ++++ lib/ace/editor.js | 95 ++++++++++++++++++++++++++++ 2 files changed, 107 insertions(+) diff --git a/lib/ace/commands/default_commands.js b/lib/ace/commands/default_commands.js index 77cdfc61..e7cb56ad 100644 --- a/lib/ace/commands/default_commands.js +++ b/lib/ace/commands/default_commands.js @@ -402,6 +402,18 @@ exports.commands = [{ exec: function(editor) { editor.jumpToMatching(true); }, multiSelectAction: "forEach", readOnly: true +}, { + name: "jumptomatchingtag", + bindKey: bindKey("Alt-P", "Alt-Shift-P"), + exec: function(editor) { editor.jumpToMatchingTag(); }, + multiSelectAction: "forEach", + readOnly: true +}, { + name: "selecttomatchingtag", + bindKey: bindKey("Alt-Shift-P", null), + exec: function(editor) { editor.jumpToMatchingTag(true); }, + multiSelectAction: "forEach", + readOnly: true }, // commands disabled in readOnly mode diff --git a/lib/ace/editor.js b/lib/ace/editor.js index ef2d9f1a..da77e185 100644 --- a/lib/ace/editor.js +++ b/lib/ace/editor.js @@ -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. @@ -1948,6 +1949,100 @@ var Editor = function(renderer, session) { } }; + /** + * Moves the cursor's row and column to the next matching tag. + * + **/ + this.jumpToMatchingTag = function(select) { + var tag; + var depth = {}; + var sel = {}; + var cursor = this.getCursorPosition(); + var iterator = new TokenIterator(this.session, cursor.row, cursor.column); + var prevToken = iterator.getCurrentToken(); + var token = iterator.stepForward(); + + //get next closing tag + if (!token || token.type.indexOf('tag-name') === -1) { + do { + prevToken = token; + token = iterator.stepForward(); + + 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==='=0)); + } + + if (token && token.type.indexOf('tag-name') !== -1) { + sel.end = { + column: iterator.getCurrentTokenColumn()-2, + row: iterator.getCurrentTokenRow() + }; + tag = token.value; + } + + //no tag found + if (!tag) { + return; + } + + //find matching tag + do { + token = prevToken; + prevToken = iterator.stepBackward(); + + if( prevToken ){ + if (prevToken.type.indexOf('tag-close') !== -1) { + sel.start = { + column: iterator.getCurrentTokenColumn()+1, + row: iterator.getCurrentTokenRow() + }; + } + + if (token.value===tag && token.type.indexOf('tag-name') !== -1 && prevToken.value==='<') { + depth[tag]++; + } else if ( token.value===tag && token.type.indexOf('tag-name') !== -1 && prevToken.value==='