From e8e8593ef42b0672eef554f77fea93e794cb1329 Mon Sep 17 00:00:00 2001 From: mkslanc Date: Fri, 7 Oct 2022 17:38:58 +0400 Subject: [PATCH 1/7] implement `getMatchingTags` method to combine different matching tags implementations; highlight both matching tags --- src/editor.js | 375 +++++++++++++++++++++++++++++++------------------- 1 file changed, 234 insertions(+), 141 deletions(-) diff --git a/src/editor.js b/src/editor.js index 351aea03f7c..a6bf581cf6e 100644 --- a/src/editor.js +++ b/src/editor.js @@ -552,110 +552,221 @@ Editor.$uid = 0; var session = self.session; if (!session || session.destroyed) return; + if (!session.$tagHighlight) session.$tagHighlight = []; var pos = self.getCursorPosition(); var iterator = new TokenIterator(self.session, pos.row, pos.column); var token = iterator.getCurrentToken(); - + if (!token || !/\b(?:tag-open|tag-name)/.test(token.type)) { - session.removeMarker(session.$tagHighlight); - session.$tagHighlight = null; + for (let i in session.$tagHighlight) { + session.removeMarker(session.$tagHighlight[i]); + } + session.$tagHighlight = []; return; } - - if (token.type.indexOf("tag-open") !== -1) { - token = iterator.stepForward(); - if (!token) - return; + + var tagNames = self.getMatchingTags(pos); + + if (!tagNames) { + for (let i in session.$tagHighlight) { + session.removeMarker(session.$tagHighlight[i]); + } + session.$tagHighlight = []; + return; } - - var tag = token.value; - var currentTag = token.value; - var depth = 0; - var prevToken = iterator.stepBackward(); - - if (prevToken.value === '<'){ - //find closing tag - do { - prevToken = token; - token = iterator.stepForward(); - - if (token) { - if (token.type.indexOf('tag-name') !== -1) { - currentTag = token.value; - if (tag === currentTag) { - if (prevToken.value === '<') { - depth++; - } else if (prevToken.value === '' && !foundOpenTagEnd) { + var openTagEnd = new Range(iterator.getCurrentTokenRow(), iterator.getCurrentTokenColumn(), + iterator.getCurrentTokenRow(), iterator.getCurrentTokenColumn() + 1 + ); + foundOpenTagEnd = true; + } + if (token.type.indexOf('tag-name') !== -1) { + currentTag = token.value; + if (tag === currentTag) { + if (prevToken.value === '<') { + depth++; + } + else if (prevToken.value === '') { + var closeTagEnd = new Range(iterator.getCurrentTokenRow(), + iterator.getCurrentTokenColumn(), iterator.getCurrentTokenRow(), + iterator.getCurrentTokenColumn() + 1 + ); + } + else { + return; + } } } - } else if (tag === currentTag && token.value === '/>') { // self closing tag - depth--; } } - - } while (token && depth >= 0); - } else { - //find opening tag - do { - token = prevToken; - prevToken = iterator.stepBackward(); - - if (token) { - if (token.type.indexOf('tag-name') !== -1) { - if (tag === token.value) { - if (prevToken.value === '<') { - depth++; - } else if (prevToken.value === '') { // self closing tag + depth--; + } + } + } while (token && depth >= 0); + } + else { + //find opening tag + var startRow = iterator.getCurrentTokenRow(); + var startColumn = iterator.getCurrentTokenColumn(); + var endColumn = startColumn + 1; + var closeTagStart = new Range(startRow, startColumn, startRow, endColumn); + iterator.stepForward(); + var closeTagName = new Range(iterator.getCurrentTokenRow(), iterator.getCurrentTokenColumn(), + iterator.getCurrentTokenRow(), iterator.getCurrentTokenColumn() + token.value.length + ); + token = iterator.stepForward(); + if (!token || token.value !== ">") return; + var closeTagEnd = new Range(iterator.getCurrentTokenRow(), iterator.getCurrentTokenColumn(), + iterator.getCurrentTokenRow(), iterator.getCurrentTokenColumn() + 1 + ); + iterator.stepBackward(); + iterator.stepBackward(); + do { + token = prevToken; + startRow = iterator.getCurrentTokenRow(); + startColumn = iterator.getCurrentTokenColumn(); + endColumn = startColumn + token.value.length; + + prevToken = iterator.stepBackward(); + + if (token) { + if (token.type.indexOf('tag-name') !== -1) { + if (tag === token.value) { + if (prevToken.value === '<') { + depth++; + if (depth > 0) { + var openTagName = new Range(startRow, startColumn, startRow, endColumn); + var openTagStart = new Range(iterator.getCurrentTokenRow(), + iterator.getCurrentTokenColumn(), iterator.getCurrentTokenRow(), + iterator.getCurrentTokenColumn() + 1 + ); + do { + token = iterator.stepForward(); + } while (token && token.value !== '>'); + var openTagEnd = new Range(iterator.getCurrentTokenRow(), + iterator.getCurrentTokenColumn(), iterator.getCurrentTokenRow(), + iterator.getCurrentTokenColumn() + 1 + ); } } - } else if (token.value === '/>') { // self closing tag - var stepCount = 0; - var tmpToken = prevToken; - while (tmpToken) { - if (tmpToken.type.indexOf('tag-name') !== -1 && tmpToken.value === tag) { - depth--; - break; - } else if (tmpToken.value === '<') { - break; - } - tmpToken = iterator.stepBackward(); - stepCount++; + else if (prevToken.value === '') { // self closing tag + var stepCount = 0; + var tmpToken = prevToken; + while (tmpToken) { + if (tmpToken.type.indexOf('tag-name') !== -1 && tmpToken.value === tag) { + depth--; + break; + } + else if (tmpToken.value === '<') { + break; } + tmpToken = iterator.stepBackward(); + stepCount++; + } + for (var i = 0; i < stepCount; i++) { + iterator.stepForward(); } } - } while (prevToken && depth <= 0); - - //select tag again - iterator.stepForward(); - } - - if (!token) { - session.removeMarker(session.$tagHighlight); - session.$tagHighlight = null; - return; - } - - var row = iterator.getCurrentTokenRow(); - var column = iterator.getCurrentTokenColumn(); - var range = new Range(row, column, row, column+token.value.length); - - //remove range if different - var sbm = session.$backMarkers[session.$tagHighlight]; - if (session.$tagHighlight && sbm != undefined && range.compareRange(sbm.range) !== 0) { - session.removeMarker(session.$tagHighlight); - session.$tagHighlight = null; - } - - if (!session.$tagHighlight) - session.$tagHighlight = session.addMarker(range, "ace_bracket", "text"); - }, 50); - }; + } + } while (prevToken && depth <= 0); + } + if (openTagStart && openTagEnd && closeTagStart && closeTagEnd && openTagName && closeTagName) { + return { + openTag: new Range(openTagStart.start.row, openTagStart.start.column, openTagEnd.end.row, + openTagEnd.end.column + ), + closeTag: new Range(closeTagStart.start.row, closeTagStart.start.column, closeTagEnd.end.row, + closeTagEnd.end.column + ), + openTagName: openTagName, + closeTagName: closeTagName + }; + } + } /** * @@ -2228,10 +2339,14 @@ Editor.$uid = 0; * Moves the cursor's row and column to the next matching bracket or HTML tag. * **/ - this.jumpToMatching = function(select, expand) { + this.jumpToMatching = function (select, expand) { var cursor = this.getCursorPosition(); var iterator = new TokenIterator(this.session, cursor.row, cursor.column); var prevToken = iterator.getCurrentToken(); + var tokenCount = 0; + if (prevToken && prevToken.type.indexOf('tag-name') !== -1) { + prevToken = iterator.stepBackward(); + } var token = prevToken || iterator.stepForward(); if (!token) return; @@ -2250,7 +2365,7 @@ Editor.$uid = 0; "{": "{", "}": "{" }; - + do { if (token.value.match(/[{}()\[\]]/g)) { for (; i < token.value.length && !found; i++) { @@ -2279,7 +2394,7 @@ Editor.$uid = 0; matchType = 'bracket'; found = true; } - break; + break; } } } @@ -2287,14 +2402,14 @@ Editor.$uid = 0; if (isNaN(depth[token.value])) { depth[token.value] = 0; } - - if (prevToken.value === '<') { + + if (prevToken.value === '<' && tokenCount > 1) { depth[token.value]++; } else if (prevToken.value === ' Date: Mon, 10 Oct 2022 18:19:30 +0400 Subject: [PATCH 2/7] highlight self-closing tags; `findMatchingTag` for vim --- src/edit_session/bracket_match.js | 185 ++++++++++++++++++++++++++++++ src/editor.js | 183 +---------------------------- src/editor_commands_test.js | 4 +- src/keyboard/vim.js | 22 +++- src/keyboard/vim_test.js | 18 +-- 5 files changed, 222 insertions(+), 190 deletions(-) diff --git a/src/edit_session/bracket_match.js b/src/edit_session/bracket_match.js index 9544f5dc12b..7e6d4899c44 100644 --- a/src/edit_session/bracket_match.js +++ b/src/edit_session/bracket_match.js @@ -219,5 +219,190 @@ function BracketMatch() { return null; }; + + /** + * Returns [[Range]]'s for matching tags and tag names, if there are any + * @param {Position} pos + * @returns {{closeTag: Range, closeTagName: Range, openTag: Range, openTagName: Range} | undefined} + */ + this.getMatchingTags = function (pos) { + var iterator = new TokenIterator(this, pos.row, pos.column); + var token = iterator.getCurrentToken(); + var found = false; + var backward = false; + if (token && token.type.indexOf('tag-name') === -1) { + do { + if (backward) token = iterator.stepBackward(); else token = iterator.stepForward(); + if (token) { + if (token.value === "/>") backward = true; + if (token.type.indexOf('tag-name') !== -1) { + found = true; + } + } + } while (token && !found); + } + if (!token) return; + + var tag = token.value; + var currentTag = token.value; + var depth = 0; + var prevToken = iterator.stepBackward(); + + if (prevToken.value === '<') { + //find closing tag + var openTagStart = new Range(iterator.getCurrentTokenRow(), iterator.getCurrentTokenColumn(), + iterator.getCurrentTokenRow(), iterator.getCurrentTokenColumn() + 1 + ); + token = iterator.stepForward(); + var openTagName = new Range(iterator.getCurrentTokenRow(), iterator.getCurrentTokenColumn(), + iterator.getCurrentTokenRow(), iterator.getCurrentTokenColumn() + token.value.length + ); + iterator.stepBackward(); + var foundOpenTagEnd = false; + do { + prevToken = token; + token = iterator.stepForward(); + if (token) { + if (token.value === '>' && !foundOpenTagEnd) { + var openTagEnd = new Range(iterator.getCurrentTokenRow(), iterator.getCurrentTokenColumn(), + iterator.getCurrentTokenRow(), iterator.getCurrentTokenColumn() + 1 + ); + foundOpenTagEnd = true; + } + if (token.type.indexOf('tag-name') !== -1) { + currentTag = token.value; + if (tag === currentTag) { + if (prevToken.value === '<') { + depth++; + } + else if (prevToken.value === '') { + var closeTagEnd = new Range(iterator.getCurrentTokenRow(), + iterator.getCurrentTokenColumn(), iterator.getCurrentTokenRow(), + iterator.getCurrentTokenColumn() + 1 + ); + } + else { + return; + } + } + } + } + } + else if (tag === currentTag && token.value === '/>') { // self closing tag + depth--; + if (depth < 0) { + var closeTagStart = new Range(iterator.getCurrentTokenRow(), + iterator.getCurrentTokenColumn(), iterator.getCurrentTokenRow(), + iterator.getCurrentTokenColumn() + 2 + ); + var closeTagName = closeTagStart; + + var openTagEnd = new Range(openTagName.end.row, openTagName.end.column, openTagName.end.row, + openTagName.end.column + 1 + ); + var closeTagEnd = closeTagName; + } + } + } + } while (token && depth >= 0); + } + else { + //find opening tag + var startRow = iterator.getCurrentTokenRow(); + var startColumn = iterator.getCurrentTokenColumn(); + var endColumn = startColumn + 1; + var closeTagStart = new Range(startRow, startColumn, startRow, endColumn); + iterator.stepForward(); + var closeTagName = new Range(iterator.getCurrentTokenRow(), iterator.getCurrentTokenColumn(), + iterator.getCurrentTokenRow(), iterator.getCurrentTokenColumn() + token.value.length + ); + token = iterator.stepForward(); + if (!token || token.value !== ">") return; + var closeTagEnd = new Range(iterator.getCurrentTokenRow(), iterator.getCurrentTokenColumn(), + iterator.getCurrentTokenRow(), iterator.getCurrentTokenColumn() + 1 + ); + iterator.stepBackward(); + iterator.stepBackward(); + do { + token = prevToken; + startRow = iterator.getCurrentTokenRow(); + startColumn = iterator.getCurrentTokenColumn(); + endColumn = startColumn + token.value.length; + + prevToken = iterator.stepBackward(); + + if (token) { + if (token.type.indexOf('tag-name') !== -1) { + if (tag === token.value) { + if (prevToken.value === '<') { + depth++; + if (depth > 0) { + var openTagName = new Range(startRow, startColumn, startRow, endColumn); + var openTagStart = new Range(iterator.getCurrentTokenRow(), + iterator.getCurrentTokenColumn(), iterator.getCurrentTokenRow(), + iterator.getCurrentTokenColumn() + 1 + ); + do { + token = iterator.stepForward(); + } while (token && token.value !== '>'); + var openTagEnd = new Range(iterator.getCurrentTokenRow(), + iterator.getCurrentTokenColumn(), iterator.getCurrentTokenRow(), + iterator.getCurrentTokenColumn() + 1 + ); + } + } + else if (prevToken.value === '') { // self closing tag + var stepCount = 0; + var tmpToken = prevToken; + while (tmpToken) { + if (tmpToken.type.indexOf('tag-name') !== -1 && tmpToken.value === tag) { + depth--; + break; + } + else if (tmpToken.value === '<') { + break; + } + tmpToken = iterator.stepBackward(); + stepCount++; + } + for (var i = 0; i < stepCount; i++) { + iterator.stepForward(); + } + } + } + } while (prevToken && depth <= 0); + } + if (openTagStart && openTagEnd && closeTagStart && closeTagEnd && openTagName && closeTagName) { + return { + openTag: new Range(openTagStart.start.row, openTagStart.start.column, openTagEnd.end.row, + openTagEnd.end.column + ), + closeTag: new Range(closeTagStart.start.row, closeTagStart.start.column, closeTagEnd.end.row, + closeTagEnd.end.column + ), + openTagName: openTagName, + closeTagName: closeTagName + }; + } + } } exports.BracketMatch = BracketMatch; diff --git a/src/editor.js b/src/editor.js index a6bf581cf6e..320c211ac46 100644 --- a/src/editor.js +++ b/src/editor.js @@ -555,7 +555,7 @@ Editor.$uid = 0; if (!session.$tagHighlight) session.$tagHighlight = []; var pos = self.getCursorPosition(); - var iterator = new TokenIterator(self.session, pos.row, pos.column); + var iterator = new TokenIterator(session, pos.row, pos.column); var token = iterator.getCurrentToken(); if (!token || !/\b(?:tag-open|tag-name)/.test(token.type)) { @@ -566,16 +566,16 @@ Editor.$uid = 0; return; } - var tagNames = self.getMatchingTags(pos); + var tagNamesRanges = session.getMatchingTags(pos); - if (!tagNames) { + if (!tagNamesRanges) { for (let i in session.$tagHighlight) { session.removeMarker(session.$tagHighlight[i]); } session.$tagHighlight = []; return; } - var ranges = [tagNames.openTagName, tagNames.closeTagName]; + var ranges = [tagNamesRanges.openTagName, tagNamesRanges.closeTagName]; //remove range if different var clean = false; @@ -595,179 +595,6 @@ Editor.$uid = 0; }, 50); }; - /** - * Returns [[Range]]'s for matching tags and tag names, if there are any - * @param {Position} pos - * @returns {{closeTag: Range, closeTagName: Range, openTag: Range, openTagName: Range} | undefined} - */ - this.getMatchingTags = function (pos) { - var iterator = new TokenIterator(this.session, pos.row, pos.column); - var token = iterator.getCurrentToken(); - var found = false; - var backward = false; - if (token.type.indexOf('tag-name') === -1) { - do { - if (!backward) token = iterator.stepForward(); else token = iterator.stepBackward(); - if (token) { - if (token.value === "<") backward = true; - if (token.type.indexOf('tag-name') !== -1) { - found = true; - } - } - } while (token && !found); - } - if (!token) return; - - var tag = token.value; - var currentTag = token.value; - var depth = 0; - var prevToken = iterator.stepBackward(); - - if (prevToken.value === '<') { - //find closing tag - var openTagStart = new Range(iterator.getCurrentTokenRow(), iterator.getCurrentTokenColumn(), - iterator.getCurrentTokenRow(), iterator.getCurrentTokenColumn() + 1 - ); - token = iterator.stepForward(); - var openTagName = new Range(iterator.getCurrentTokenRow(), iterator.getCurrentTokenColumn(), - iterator.getCurrentTokenRow(), iterator.getCurrentTokenColumn() + token.value.length - ); - iterator.stepBackward(); - var foundOpenTagEnd = false; - do { - prevToken = token; - token = iterator.stepForward(); - if (token) { - if (token.value === '>' && !foundOpenTagEnd) { - var openTagEnd = new Range(iterator.getCurrentTokenRow(), iterator.getCurrentTokenColumn(), - iterator.getCurrentTokenRow(), iterator.getCurrentTokenColumn() + 1 - ); - foundOpenTagEnd = true; - } - if (token.type.indexOf('tag-name') !== -1) { - currentTag = token.value; - if (tag === currentTag) { - if (prevToken.value === '<') { - depth++; - } - else if (prevToken.value === '') { - var closeTagEnd = new Range(iterator.getCurrentTokenRow(), - iterator.getCurrentTokenColumn(), iterator.getCurrentTokenRow(), - iterator.getCurrentTokenColumn() + 1 - ); - } - else { - return; - } - } - } - } - } - else if (tag === currentTag && token.value === '/>') { // self closing tag - depth--; - } - } - } while (token && depth >= 0); - } - else { - //find opening tag - var startRow = iterator.getCurrentTokenRow(); - var startColumn = iterator.getCurrentTokenColumn(); - var endColumn = startColumn + 1; - var closeTagStart = new Range(startRow, startColumn, startRow, endColumn); - iterator.stepForward(); - var closeTagName = new Range(iterator.getCurrentTokenRow(), iterator.getCurrentTokenColumn(), - iterator.getCurrentTokenRow(), iterator.getCurrentTokenColumn() + token.value.length - ); - token = iterator.stepForward(); - if (!token || token.value !== ">") return; - var closeTagEnd = new Range(iterator.getCurrentTokenRow(), iterator.getCurrentTokenColumn(), - iterator.getCurrentTokenRow(), iterator.getCurrentTokenColumn() + 1 - ); - iterator.stepBackward(); - iterator.stepBackward(); - do { - token = prevToken; - startRow = iterator.getCurrentTokenRow(); - startColumn = iterator.getCurrentTokenColumn(); - endColumn = startColumn + token.value.length; - - prevToken = iterator.stepBackward(); - - if (token) { - if (token.type.indexOf('tag-name') !== -1) { - if (tag === token.value) { - if (prevToken.value === '<') { - depth++; - if (depth > 0) { - var openTagName = new Range(startRow, startColumn, startRow, endColumn); - var openTagStart = new Range(iterator.getCurrentTokenRow(), - iterator.getCurrentTokenColumn(), iterator.getCurrentTokenRow(), - iterator.getCurrentTokenColumn() + 1 - ); - do { - token = iterator.stepForward(); - } while (token && token.value !== '>'); - var openTagEnd = new Range(iterator.getCurrentTokenRow(), - iterator.getCurrentTokenColumn(), iterator.getCurrentTokenRow(), - iterator.getCurrentTokenColumn() + 1 - ); - } - } - else if (prevToken.value === '') { // self closing tag - var stepCount = 0; - var tmpToken = prevToken; - while (tmpToken) { - if (tmpToken.type.indexOf('tag-name') !== -1 && tmpToken.value === tag) { - depth--; - break; - } - else if (tmpToken.value === '<') { - break; - } - tmpToken = iterator.stepBackward(); - stepCount++; - } - for (var i = 0; i < stepCount; i++) { - iterator.stepForward(); - } - } - } - } while (prevToken && depth <= 0); - } - if (openTagStart && openTagEnd && closeTagStart && closeTagEnd && openTagName && closeTagName) { - return { - openTag: new Range(openTagStart.start.row, openTagStart.start.column, openTagEnd.end.row, - openTagEnd.end.column - ), - closeTag: new Range(closeTagStart.start.row, closeTagStart.start.column, closeTagEnd.end.row, - closeTagEnd.end.column - ), - openTagName: openTagName, - closeTagName: closeTagName - }; - } - } - /** * * Brings the current `textInput` into focus. @@ -2447,7 +2274,7 @@ Editor.$uid = 0; //find matching tag if (range.compare(cursor.row, cursor.column) === 0) { - var tagsRanges = this.getMatchingTags(cursor); + var tagsRanges = this.session.getMatchingTags(cursor); if (tagsRanges) { if (tagsRanges.openTag.contains(cursor.row, cursor.column)) { range = tagsRanges.closeTag; diff --git a/src/editor_commands_test.js b/src/editor_commands_test.js index adf52389859..21a9aaa2b88 100644 --- a/src/editor_commands_test.js +++ b/src/editor_commands_test.js @@ -230,14 +230,14 @@ module.exports = { exec("gotoright", 15); editor.execCommand(editor.commands.byName.selecttomatching); editor.execCommand(editor.commands.byName.selecttomatching); - assert.range(editor.selection.getRange(), 0, 6, 0, 15); + assert.range(editor.selection.getRange(), 0, 10, 0, 15); editor.setValue("abcd", 1); exec("gotostart", 1); exec("gotoright", 21); editor.execCommand(editor.commands.byName.selecttomatching); editor.execCommand(editor.commands.byName.selecttomatching); - assert.range(editor.selection.getRange(), 0, 6, 0, 21); + assert.range(editor.selection.getRange(), 0, 16, 0, 21); editor.setValue("", 1); exec("gotostart", 1); diff --git a/src/keyboard/vim.js b/src/keyboard/vim.js index b029cba37eb..b8756d21f4e 100644 --- a/src/keyboard/vim.js +++ b/src/keyboard/vim.js @@ -136,8 +136,12 @@ }; - CodeMirror.findMatchingTag = function(cm, head) { - + CodeMirror.findMatchingTag = function (cm, head) { + return cm.findMatchingTag(head); + } + + CodeMirror.findEnclosingTag = function (cm, head) { + }; CodeMirror.signal = function(o, name, e) { return o._signal(name, e) }; @@ -613,6 +617,20 @@ var m = this.ace.session.findMatchingBracket(toAcePos(pos)); return {to: m && toCmPos(m)}; }; + this.findMatchingTag = function (pos) { + var m = this.ace.session.getMatchingTags(toAcePos(pos)); + if (!m) return; + return { + open: { + from: toCmPos(m.openTag.start), + to: toCmPos(m.openTag.end) + }, + close: { + from: toCmPos(m.closeTag.start), + to: toCmPos(m.closeTag.end) + } + }; + }; this.indentLine = function(line, method) { if (method === true) this.ace.session.indentRows(line, line, "\t"); diff --git a/src/keyboard/vim_test.js b/src/keyboard/vim_test.js index 7503adb811b..a1f9667db89 100644 --- a/src/keyboard/vim_test.js +++ b/src/keyboard/vim_test.js @@ -1665,25 +1665,27 @@ testEdit('di>_middle_spc', 'a\t<\n\tbar\n>b', /r/, 'di>', 'a\t<>b'); testEdit('da<_middle_spc', 'a\t<\n\tbar\n>b', /r/, 'da<', 'a\tb'); testEdit('da>_middle_spc', 'a\t<\n\tbar\n>b', /r/, 'da>', 'a\tb'); -// deleting tag objects -isAce || testEdit('dat_noop', 'hello', /n/, 'dat', 'hello'); -isAce || testEdit('dat_open_tag', 'hello', /n/, 'dat', '', { +//TODO: mode changing is not implemented for vim +isAce || testEdit('dat_noop', 'hello', /n/, 'dat', 'hello',{ + mode: 'text' +}); +testEdit('dat_open_tag', 'hello', /n/, 'dat', '', { mode: 'xml' }); -isAce || testEdit('dat_inside_tag', 'hello', /l/, 'dat', '', { +testEdit('dat_inside_tag', 'hello', /l/, 'dat', '', { mode: 'xml' }); -isAce || testEdit('dat_close_tag', 'hello', /\//, 'dat', '', { +testEdit('dat_close_tag', 'hello', /\//, 'dat', '', { mode: 'xml' }); -isAce || testEdit('dit_open_tag', 'hello', /n/, 'dit', '', { +testEdit('dit_open_tag', 'hello', /n/, 'dit', '', { mode: 'xml' }); -isAce || testEdit('dit_inside_tag', 'hello', /l/, 'dit', '', { +testEdit('dit_inside_tag', 'hello', /l/, 'dit', '', { mode: 'xml' }); -isAce || testEdit('dit_close_tag', 'hello', /\//, 'dit', '', { +testEdit('dit_close_tag', 'hello', /\//, 'dit', '', { mode: 'xml' }); From 7c93f2db419b07c6c09f1a55e8ad25f36b8e085b Mon Sep 17 00:00:00 2001 From: mkslanc Date: Mon, 10 Oct 2022 18:21:05 +0400 Subject: [PATCH 3/7] use `getMatchingTags` for xml/html `getFoldWidgetRange` --- src/mode/folding/xml.js | 146 ++-------------------------------------- 1 file changed, 6 insertions(+), 140 deletions(-) diff --git a/src/mode/folding/xml.js b/src/mode/folding/xml.js index a59920957bb..076431184cb 100644 --- a/src/mode/folding/xml.js +++ b/src/mode/folding/xml.js @@ -1,10 +1,8 @@ "use strict"; var oop = require("../../lib/oop"); -var lang = require("../../lib/lang"); var Range = require("../../range").Range; var BaseFoldMode = require("./fold_mode").FoldMode; -var TokenIterator = require("../../token_iterator").TokenIterator; var FoldMode = exports.FoldMode = function(voidElements, optionalEndTags) { BaseFoldMode.call(this); @@ -37,7 +35,7 @@ function is(token, type) { return this.getCommentFoldWidget(session, row); if (tag.closing || (!tag.tagName && tag.selfClosing)) - return foldStyle == "markbeginend" ? "end" : ""; + return foldStyle === "markbeginend" ? "end" : ""; if (!tag.tagName || tag.selfClosing || this.voidElements.hasOwnProperty(tag.tagName.toLowerCase())) return ""; @@ -107,147 +105,15 @@ function is(token, type) { return false; }; - /* - * reads a full tag and places the iterator after the tag - */ - this._readTagForward = function(iterator) { - var token = iterator.getCurrentToken(); - if (!token) - return null; - - var tag = new Tag(); - do { - if (is(token, "tag-open")) { - tag.closing = is(token, "end-tag-open"); - tag.start.row = iterator.getCurrentTokenRow(); - tag.start.column = iterator.getCurrentTokenColumn(); - } else if (is(token, "tag-name")) { - tag.tagName = token.value; - } else if (is(token, "tag-close")) { - tag.selfClosing = token.value == "/>"; - tag.end.row = iterator.getCurrentTokenRow(); - tag.end.column = iterator.getCurrentTokenColumn() + token.value.length; - iterator.stepForward(); - return tag; - } - } while(token = iterator.stepForward()); - - return null; - }; - - this._readTagBackward = function(iterator) { - var token = iterator.getCurrentToken(); - if (!token) - return null; - - var tag = new Tag(); - do { - if (is(token, "tag-open")) { - tag.closing = is(token, "end-tag-open"); - tag.start.row = iterator.getCurrentTokenRow(); - tag.start.column = iterator.getCurrentTokenColumn(); - iterator.stepBackward(); - return tag; - } else if (is(token, "tag-name")) { - tag.tagName = token.value; - } else if (is(token, "tag-close")) { - tag.selfClosing = token.value == "/>"; - tag.end.row = iterator.getCurrentTokenRow(); - tag.end.column = iterator.getCurrentTokenColumn() + token.value.length; - } - } while(token = iterator.stepBackward()); - - return null; - }; - - this._pop = function(stack, tag) { - while (stack.length) { - - var top = stack[stack.length-1]; - if (!tag || top.tagName == tag.tagName) { - return stack.pop(); - } - else if (this.optionalEndTags.hasOwnProperty(top.tagName)) { - stack.pop(); - continue; - } else { - return null; - } - } - }; - this.getFoldWidgetRange = function(session, foldStyle, row) { - var firstTag = this._getFirstTagInLine(session, row); - - if (!firstTag) { + var tags = session.getMatchingTags({row: row, column: 0}); + if (tags) { + return new Range( + tags.openTag.end.row, tags.openTag.end.column, tags.closeTag.start.row, tags.closeTag.start.column); + } else { return this.getCommentFoldWidget(session, row) && session.getCommentFoldRange(row, session.getLine(row).length); } - - var isBackward = firstTag.closing || firstTag.selfClosing; - var stack = []; - var tag; - - if (!isBackward) { - var iterator = new TokenIterator(session, row, firstTag.start.column); - var start = { - row: row, - column: firstTag.start.column + firstTag.tagName.length + 2 - }; - if (firstTag.start.row == firstTag.end.row) - start.column = firstTag.end.column; - while (tag = this._readTagForward(iterator)) { - if (tag.selfClosing) { - if (!stack.length) { - tag.start.column += tag.tagName.length + 2; - tag.end.column -= 2; - return Range.fromPoints(tag.start, tag.end); - } else - continue; - } - - if (tag.closing) { - this._pop(stack, tag); - if (stack.length == 0) - return Range.fromPoints(start, tag.start); - } - else { - stack.push(tag); - } - } - } - else { - var iterator = new TokenIterator(session, row, firstTag.end.column); - var end = { - row: row, - column: firstTag.start.column - }; - - while (tag = this._readTagBackward(iterator)) { - if (tag.selfClosing) { - if (!stack.length) { - tag.start.column += tag.tagName.length + 2; - tag.end.column -= 2; - return Range.fromPoints(tag.start, tag.end); - } else - continue; - } - - if (!tag.closing) { - this._pop(stack, tag); - if (stack.length == 0) { - tag.start.column += tag.tagName.length + 2; - if (tag.start.row == tag.end.row && tag.start.column < tag.end.column) - tag.start.column = tag.end.column; - return Range.fromPoints(tag.start, end); - } - } - else { - stack.push(tag); - } - } - } - }; }).call(FoldMode.prototype); From 978d9edf4b0e712868981ec5297cdcfd3e810cf9 Mon Sep 17 00:00:00 2001 From: mkslanc Date: Mon, 10 Oct 2022 19:00:38 +0400 Subject: [PATCH 4/7] combine `$highlightTags` and `$highlightBrackets` --- src/editor.js | 71 +++++++------------------------------ src/editor_commands_test.js | 10 +++--- src/layer/text.js | 6 ++-- 3 files changed, 21 insertions(+), 66 deletions(-) diff --git a/src/editor.js b/src/editor.js index 320c211ac46..47580fc7493 100644 --- a/src/editor.js +++ b/src/editor.js @@ -506,8 +506,18 @@ Editor.$uid = 0; }); session.$bracketHighlight = null; } - var ranges = session.getMatchingBracketRanges(self.getCursorPosition()); - if (!ranges && session.$mode.getMatching) + var pos = self.getCursorPosition(); + var ranges = session.getMatchingBracketRanges(pos); + if (!ranges) { + var iterator = new TokenIterator(session, pos.row, pos.column); + var token = iterator.getCurrentToken(); + + if (token && /\b(?:tag-open|tag-name)/.test(token.type)) { + var tagNamesRanges = session.getMatchingTags(pos); + if (tagNamesRanges) ranges = [tagNamesRanges.openTagName, tagNamesRanges.closeTagName]; + } + } + if (!ranges && session.$mode.getMatching) ranges = session.$mode.getMatching(self.session); if (!ranges) { if (self.getHighlightIndentGuides()) self.renderer.$textLayer.$highlightIndentGuide(); @@ -539,62 +549,6 @@ Editor.$uid = 0; }, 50); }; - // todo: move to mode.getMatching - this.$highlightTags = function() { - if (this.$highlightTagPending) - return; - - // perform highlight async to not block the browser during navigation - var self = this; - this.$highlightTagPending = true; - setTimeout(function() { - self.$highlightTagPending = false; - - var session = self.session; - if (!session || session.destroyed) return; - if (!session.$tagHighlight) session.$tagHighlight = []; - - var pos = self.getCursorPosition(); - var iterator = new TokenIterator(session, pos.row, pos.column); - var token = iterator.getCurrentToken(); - - if (!token || !/\b(?:tag-open|tag-name)/.test(token.type)) { - for (let i in session.$tagHighlight) { - session.removeMarker(session.$tagHighlight[i]); - } - session.$tagHighlight = []; - return; - } - - var tagNamesRanges = session.getMatchingTags(pos); - - if (!tagNamesRanges) { - for (let i in session.$tagHighlight) { - session.removeMarker(session.$tagHighlight[i]); - } - session.$tagHighlight = []; - return; - } - var ranges = [tagNamesRanges.openTagName, tagNamesRanges.closeTagName]; - - //remove range if different - var clean = false; - for (let i in session.$tagHighlight) { - var sbm = session.$backMarkers[session.$tagHighlight[i]]; - if (session.$tagHighlight[i] && sbm !== undefined && ranges[i].compareRange(sbm.range) !== 0) { - session.removeMarker(session.$tagHighlight[i]); - clean = true; - } - } - if (clean) session.$tagHighlight = []; - - for (let i in ranges) { - if (!session.$tagHighlight[i]) - session.$tagHighlight[i] = session.addMarker(ranges[i], "ace_bracket", "text"); - } - }, 50); - }; - /** * * Brings the current `textInput` into focus. @@ -652,7 +606,6 @@ Editor.$uid = 0; this.$cursorChange = function() { this.renderer.updateCursor(); this.$highlightBrackets(); - this.$highlightTags(); this.$updateHighlightActiveLine(); }; diff --git a/src/editor_commands_test.js b/src/editor_commands_test.js index 21a9aaa2b88..ce9fc657d9d 100644 --- a/src/editor_commands_test.js +++ b/src/editor_commands_test.js @@ -29,15 +29,15 @@ module.exports = { editor.setValue(" abcd", 1); exec("gotostart", 1); exec("gotoright", 3); - assert.equal(editor.$highlightTagPending, true); + assert.equal(editor.$highlightPending, true); setTimeout(function() { - assert.equal(editor.$highlightTagPending, false); - assert.ok(editor.session.$tagHighlight); + assert.equal(editor.$highlightPending, false); + assert.ok(editor.session.$bracketHighlight); exec("gotoend", 1); exec("gotoleft", 3); - assert.equal(editor.$highlightTagPending, true); + assert.equal(editor.$highlightPending, true); setTimeout(function() { - assert.equal(editor.$highlightTagPending, false); + assert.equal(editor.$highlightPending, false); done(); }, 51); }, 51); diff --git a/src/layer/text.js b/src/layer/text.js index 4c20be050e9..aa3be47f9cf 100644 --- a/src/layer/text.js +++ b/src/layer/text.js @@ -500,8 +500,10 @@ var Text = function(parentEl) { var line = this.session.doc.getLine(cell.row); if (line !== "") { var childNodes = cell.element.childNodes; - if (childNodes && childNodes[indentLevel - 1] && childNodes[indentLevel - 1].classList) { - childNodes[indentLevel - 1].classList.add("ace_indent-guide-active"); + if (childNodes) { + let node = childNodes[indentLevel - 1]; + if (node && node.classList && node.classList.contains("ace_indent-guide")) node.classList.add( + "ace_indent-guide-active"); } } }; From e8c0a1f35d302966626896aaf84b056e76a8e66e Mon Sep 17 00:00:00 2001 From: mkslanc Date: Mon, 10 Oct 2022 19:45:47 +0400 Subject: [PATCH 5/7] fix: `MockDom's` `ClassList` `toggle` and `contains` methods return `boolean` instead of `void` --- src/edit_session/bracket_match.js | 2 +- src/test/mockdom.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/edit_session/bracket_match.js b/src/edit_session/bracket_match.js index 7e6d4899c44..2e88214f626 100644 --- a/src/edit_session/bracket_match.js +++ b/src/edit_session/bracket_match.js @@ -403,6 +403,6 @@ function BracketMatch() { closeTagName: closeTagName }; } - } + }; } exports.BracketMatch = BracketMatch; diff --git a/src/test/mockdom.js b/src/test/mockdom.js index b64b79c405b..e0c65ddddae 100644 --- a/src/test/mockdom.js +++ b/src/test/mockdom.js @@ -41,10 +41,10 @@ function ClassList(node) { dom.removeCssClass(this.el, str); }; this.toggle = function(str) { - dom.toggleCssClass(this.el, str); + return dom.toggleCssClass(this.el, str); }; this.contains = function(str) { - dom.hasCssClass(this.el, str); + return dom.hasCssClass(this.el, str); }; }).call(ClassList.prototype); From 236a31e5d69fd4fd874b667b38dd1bf0685f75c5 Mon Sep 17 00:00:00 2001 From: mkslanc Date: Tue, 11 Oct 2022 12:28:02 +0400 Subject: [PATCH 6/7] fix: mode change for vim tests --- src/keyboard/vim_test.js | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/keyboard/vim_test.js b/src/keyboard/vim_test.js index a1f9667db89..c877cd50029 100644 --- a/src/keyboard/vim_test.js +++ b/src/keyboard/vim_test.js @@ -9,6 +9,8 @@ var Editor = require("./../editor").Editor; var UndoManager = require("./../undomanager").UndoManager; var MockRenderer = require("./../test/mockrenderer").MockRenderer; var JavaScriptMode = require("./../mode/javascript").Mode; +var CSSMode = require("./../mode/css").Mode; +var XMLMode = require("./../mode/xml").Mode; var VirtualRenderer = require("./../virtual_renderer").VirtualRenderer; var assert = require("./../test/assertions"); var keys = require("./../lib/keys"); @@ -28,10 +30,14 @@ var phantom = window.name == "nodejs"; var renderer = new VirtualRenderer(el); var editor = window.editor = new Editor(renderer); editor.session.setUndoManager(new UndoManager()); +var modes = { + js: new JavaScriptMode(), + css: new CSSMode(), + xml: new XMLMode() +}; editor.setOptions({ useWorker: false, behavioursEnabled: false, - mode: new JavaScriptMode(), }); function CodeMirror(place, opts) { var cm = editor.state && editor.state.cm; @@ -48,6 +54,7 @@ function CodeMirror(place, opts) { editor.setOption("indentedSoftWrap", false); editor.setOption("wrap", opts.lineWrapping); editor.setOption("useSoftTabs", !opts.indentWithTabs); + editor.setOption("mode", opts.mode ? modes[opts.mode] : modes.js); cm.setOption("tabSize", opts.tabSize || 4); cm.setOption("indentUnit", opts.indentUnit || 2); @@ -1665,9 +1672,8 @@ testEdit('di>_middle_spc', 'a\t<\n\tbar\n>b', /r/, 'di>', 'a\t<>b'); testEdit('da<_middle_spc', 'a\t<\n\tbar\n>b', /r/, 'da<', 'a\tb'); testEdit('da>_middle_spc', 'a\t<\n\tbar\n>b', /r/, 'da>', 'a\tb'); -//TODO: mode changing is not implemented for vim -isAce || testEdit('dat_noop', 'hello', /n/, 'dat', 'hello',{ - mode: 'text' +testEdit('dat_noop', 'hello', /n/, 'dat', 'hello',{ + mode: 'css' }); testEdit('dat_open_tag', 'hello', /n/, 'dat', '', { mode: 'xml' From 62574e3ec8fa310928a388fcd7027e5db9a68e4b Mon Sep 17 00:00:00 2001 From: mkslanc Date: Fri, 14 Oct 2022 16:20:45 +0400 Subject: [PATCH 7/7] refactor `getMatchingTags` --- src/edit_session/bracket_match.js | 300 +++++++++++++++++------------- 1 file changed, 170 insertions(+), 130 deletions(-) diff --git a/src/edit_session/bracket_match.js b/src/edit_session/bracket_match.js index 2e88214f626..1883d2c722b 100644 --- a/src/edit_session/bracket_match.js +++ b/src/edit_session/bracket_match.js @@ -227,6 +227,20 @@ function BracketMatch() { */ this.getMatchingTags = function (pos) { var iterator = new TokenIterator(this, pos.row, pos.column); + var token = this.$findTagName(iterator); + if (!token) return; + + var prevToken = iterator.stepBackward(); + + if (prevToken.value === '<') { + return this.$findClosingTag(iterator, token); + } + else { + return this.$findOpeningTag(iterator, token); + } + }; + + this.$findTagName = function (iterator) { var token = iterator.getCurrentToken(); var found = false; var backward = false; @@ -234,163 +248,189 @@ function BracketMatch() { do { if (backward) token = iterator.stepBackward(); else token = iterator.stepForward(); if (token) { - if (token.value === "/>") backward = true; - if (token.type.indexOf('tag-name') !== -1) { + if (token.value === "/>") { + //changing iterator direction for self-closing tags, when cursor is in between tag + //name and tag closing + backward = true; + } + else if (token.type.indexOf('tag-name') !== -1) { found = true; } } } while (token && !found); } - if (!token) return; + return token; + }; - var tag = token.value; + this.$findClosingTag = function (iterator, token) { + var prevToken; var currentTag = token.value; + var tag = token.value; var depth = 0; - var prevToken = iterator.stepBackward(); - if (prevToken.value === '<') { - //find closing tag - var openTagStart = new Range(iterator.getCurrentTokenRow(), iterator.getCurrentTokenColumn(), - iterator.getCurrentTokenRow(), iterator.getCurrentTokenColumn() + 1 - ); + var openTagStart = new Range(iterator.getCurrentTokenRow(), iterator.getCurrentTokenColumn(), + iterator.getCurrentTokenRow(), iterator.getCurrentTokenColumn() + 1 + ); + token = iterator.stepForward(); + var openTagName = new Range(iterator.getCurrentTokenRow(), iterator.getCurrentTokenColumn(), + iterator.getCurrentTokenRow(), iterator.getCurrentTokenColumn() + token.value.length + ); + var foundOpenTagEnd = false; + do { + prevToken = token; token = iterator.stepForward(); - var openTagName = new Range(iterator.getCurrentTokenRow(), iterator.getCurrentTokenColumn(), - iterator.getCurrentTokenRow(), iterator.getCurrentTokenColumn() + token.value.length - ); - iterator.stepBackward(); - var foundOpenTagEnd = false; - do { - prevToken = token; - token = iterator.stepForward(); - if (token) { - if (token.value === '>' && !foundOpenTagEnd) { - var openTagEnd = new Range(iterator.getCurrentTokenRow(), iterator.getCurrentTokenColumn(), - iterator.getCurrentTokenRow(), iterator.getCurrentTokenColumn() + 1 - ); - foundOpenTagEnd = true; - } - if (token.type.indexOf('tag-name') !== -1) { - currentTag = token.value; - if (tag === currentTag) { - if (prevToken.value === '<') { - depth++; - } - else if (prevToken.value === '' && !foundOpenTagEnd) { + var openTagEnd = new Range(iterator.getCurrentTokenRow(), iterator.getCurrentTokenColumn(), + iterator.getCurrentTokenRow(), iterator.getCurrentTokenColumn() + 1 + ); //Range for `>` + foundOpenTagEnd = true; + } + if (token.type.indexOf('tag-name') !== -1) { + currentTag = token.value; + if (tag === currentTag) { + if (prevToken.value === '<') { + depth++; + } + else if (prevToken.value === '') { + var closeTagEnd = new Range(iterator.getCurrentTokenRow(), iterator.getCurrentTokenColumn(), iterator.getCurrentTokenRow(), - iterator.getCurrentTokenColumn() + token.value.length - ); - token = iterator.stepForward(); - if (token && token.value === '>') { - var closeTagEnd = new Range(iterator.getCurrentTokenRow(), - iterator.getCurrentTokenColumn(), iterator.getCurrentTokenRow(), - iterator.getCurrentTokenColumn() + 1 - ); - } - else { - return; - } + iterator.getCurrentTokenColumn() + 1 + ); //Range for > + } + else { + return; } } } } - else if (tag === currentTag && token.value === '/>') { // self closing tag - depth--; - if (depth < 0) { - var closeTagStart = new Range(iterator.getCurrentTokenRow(), - iterator.getCurrentTokenColumn(), iterator.getCurrentTokenRow(), - iterator.getCurrentTokenColumn() + 2 - ); - var closeTagName = closeTagStart; - - var openTagEnd = new Range(openTagName.end.row, openTagName.end.column, openTagName.end.row, - openTagName.end.column + 1 - ); - var closeTagEnd = closeTagName; - } + } + else if (tag === currentTag && token.value === '/>') { // self-closing tag + depth--; + if (depth < 0) {//found self-closing tag end + //Example: + //`` - closing part of tag consist of `closeTagStart`, `closeTagName` and `closeTagEnd` + var closeTagStart = new Range(iterator.getCurrentTokenRow(), iterator.getCurrentTokenColumn(), + iterator.getCurrentTokenRow(), iterator.getCurrentTokenColumn() + 2 + ); + var closeTagName = closeTagStart; + var closeTagEnd = closeTagName; + + var openTagEnd = new Range(openTagName.end.row, openTagName.end.column, openTagName.end.row, + openTagName.end.column + 1 + ); + } } - } while (token && depth >= 0); + } + } while (token && depth >= 0); + + if (openTagStart && openTagEnd && closeTagStart && closeTagEnd && openTagName && closeTagName) { + return { + openTag: new Range(openTagStart.start.row, openTagStart.start.column, openTagEnd.end.row, + openTagEnd.end.column + ), + closeTag: new Range(closeTagStart.start.row, closeTagStart.start.column, closeTagEnd.end.row, + closeTagEnd.end.column + ), + openTagName: openTagName, + closeTagName: closeTagName + }; } - else { - //find opening tag - var startRow = iterator.getCurrentTokenRow(); - var startColumn = iterator.getCurrentTokenColumn(); - var endColumn = startColumn + 1; - var closeTagStart = new Range(startRow, startColumn, startRow, endColumn); - iterator.stepForward(); - var closeTagName = new Range(iterator.getCurrentTokenRow(), iterator.getCurrentTokenColumn(), - iterator.getCurrentTokenRow(), iterator.getCurrentTokenColumn() + token.value.length - ); - token = iterator.stepForward(); - if (!token || token.value !== ">") return; - var closeTagEnd = new Range(iterator.getCurrentTokenRow(), iterator.getCurrentTokenColumn(), - iterator.getCurrentTokenRow(), iterator.getCurrentTokenColumn() + 1 - ); - iterator.stepBackward(); - iterator.stepBackward(); - do { - token = prevToken; - startRow = iterator.getCurrentTokenRow(); - startColumn = iterator.getCurrentTokenColumn(); - endColumn = startColumn + token.value.length; + }; - prevToken = iterator.stepBackward(); + this.$findOpeningTag = function (iterator, token) { + var prevToken = iterator.getCurrentToken(); + var tag = token.value; + var depth = 0; - if (token) { - if (token.type.indexOf('tag-name') !== -1) { - if (tag === token.value) { - if (prevToken.value === '<') { - depth++; - if (depth > 0) { - var openTagName = new Range(startRow, startColumn, startRow, endColumn); - var openTagStart = new Range(iterator.getCurrentTokenRow(), - iterator.getCurrentTokenColumn(), iterator.getCurrentTokenRow(), - iterator.getCurrentTokenColumn() + 1 - ); - do { - token = iterator.stepForward(); - } while (token && token.value !== '>'); - var openTagEnd = new Range(iterator.getCurrentTokenRow(), - iterator.getCurrentTokenColumn(), iterator.getCurrentTokenRow(), - iterator.getCurrentTokenColumn() + 1 - ); - } - } - else if (prevToken.value === '") return; + var closeTagEnd = new Range(iterator.getCurrentTokenRow(), iterator.getCurrentTokenColumn(), + iterator.getCurrentTokenRow(), iterator.getCurrentTokenColumn() + 1 + ); //Range for > + + iterator.stepBackward(); + iterator.stepBackward(); + do { + token = prevToken; + startRow = iterator.getCurrentTokenRow(); + startColumn = iterator.getCurrentTokenColumn(); + endColumn = startColumn + token.value.length; + + prevToken = iterator.stepBackward(); + + if (token) { + if (token.type.indexOf('tag-name') !== -1) { + if (tag === token.value) { + if (prevToken.value === '<') { + depth++; + if (depth > 0) {//found opening tag + var openTagName = new Range(startRow, startColumn, startRow, endColumn); + var openTagStart = new Range(iterator.getCurrentTokenRow(), + iterator.getCurrentTokenColumn(), iterator.getCurrentTokenRow(), + iterator.getCurrentTokenColumn() + 1 + ); //Range for < + do { + token = iterator.stepForward(); + } while (token && token.value !== '>'); + var openTagEnd = new Range(iterator.getCurrentTokenRow(), + iterator.getCurrentTokenColumn(), iterator.getCurrentTokenRow(), + iterator.getCurrentTokenColumn() + 1 + ); //Range for > } } + else if (prevToken.value === '') { // self closing tag - var stepCount = 0; - var tmpToken = prevToken; - while (tmpToken) { - if (tmpToken.type.indexOf('tag-name') !== -1 && tmpToken.value === tag) { - depth--; - break; - } - else if (tmpToken.value === '<') { - break; - } - tmpToken = iterator.stepBackward(); - stepCount++; + } + else if (token.value === '/>') { // self-closing tag + var stepCount = 0; + var tmpToken = prevToken; + while (tmpToken) { + if (tmpToken.type.indexOf('tag-name') !== -1 && tmpToken.value === tag) { + depth--; + break; } - for (var i = 0; i < stepCount; i++) { - iterator.stepForward(); + else if (tmpToken.value === '<') { + break; } + tmpToken = iterator.stepBackward(); + stepCount++; + } + for (var i = 0; i < stepCount; i++) { + iterator.stepForward(); } } - } while (prevToken && depth <= 0); - } + } + } while (prevToken && depth <= 0); + if (openTagStart && openTagEnd && closeTagStart && closeTagEnd && openTagName && closeTagName) { return { openTag: new Range(openTagStart.start.row, openTagStart.start.column, openTagEnd.end.row,