mirror of
https://github.com/atom/atom.git
synced 2026-02-12 15:45:23 -05:00
262 lines
8.7 KiB
JavaScript
262 lines
8.7 KiB
JavaScript
/* ***** BEGIN LICENSE BLOCK *****
|
|
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
|
*
|
|
* The contents of this file are subject to the Mozilla Public License Version
|
|
* 1.1 (the "License"); you may not use this file except in compliance with
|
|
* the License. You may obtain a copy of the License at
|
|
* http://www.mozilla.org/MPL/
|
|
*
|
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
|
* for the specific language governing rights and limitations under the
|
|
* License.
|
|
*
|
|
* The Original Code is Ajax.org Code Editor (ACE).
|
|
*
|
|
* The Initial Developer of the Original Code is
|
|
* Ajax.org B.V.
|
|
* Portions created by the Initial Developer are Copyright (C) 2010
|
|
* the Initial Developer. All Rights Reserved.
|
|
*
|
|
* Contributor(s):
|
|
* Fabian Jakobs <fabian AT ajax DOT org>
|
|
*
|
|
* Alternatively, the contents of this file may be used under the terms of
|
|
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
|
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
|
* in which case the provisions of the GPL or the LGPL are applicable instead
|
|
* of those above. If you wish to allow use of your version of this file only
|
|
* under the terms of either the GPL or the LGPL, and not to allow others to
|
|
* use your version of this file under the terms of the MPL, indicate your
|
|
* decision by deleting the provisions above and replace them with the notice
|
|
* and other provisions required by the GPL or the LGPL. If you do not delete
|
|
* the provisions above, a recipient may use your version of this file under
|
|
* the terms of any one of the MPL, the GPL or the LGPL.
|
|
*
|
|
* ***** END LICENSE BLOCK ***** */
|
|
|
|
define(function(require, exports, module) {
|
|
"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) {
|
|
BaseFoldMode.call(this);
|
|
this.voidElements = voidElements || {};
|
|
};
|
|
oop.inherits(FoldMode, BaseFoldMode);
|
|
|
|
(function() {
|
|
|
|
this.getFoldWidget = function(session, foldStyle, row) {
|
|
var tag = this._getFirstTagInLine(session, row);
|
|
|
|
if (tag.closing)
|
|
return foldStyle == "markbeginend" ? "end" : "";
|
|
|
|
if (!tag.tagName || this.voidElements[tag.tagName.toLowerCase()])
|
|
return "";
|
|
|
|
if (tag.selfClosing)
|
|
return "";
|
|
|
|
if (tag.value.indexOf("/" + tag.tagName) !== -1)
|
|
return "";
|
|
|
|
return "start";
|
|
};
|
|
|
|
this._getFirstTagInLine = function(session, row) {
|
|
var tokens = session.getTokens(row, row)[0].tokens;
|
|
var value = "";
|
|
for (var i = 0; i < tokens.length; i++) {
|
|
var token = tokens[i];
|
|
if (token.type.indexOf("meta.tag") === 0)
|
|
value += token.value;
|
|
else
|
|
value += lang.stringRepeat(" ", token.value.length);
|
|
}
|
|
|
|
return this._parseTag(value);
|
|
};
|
|
|
|
this.tagRe = /^(\s*)(<?(\/?)([-_a-zA-Z0-9:!]*)\s*(\/?)>?)/;
|
|
this._parseTag = function(tag) {
|
|
|
|
var match = this.tagRe.exec(tag);
|
|
var column = this.tagRe.lastIndex || 0;
|
|
this.tagRe.lastIndex = 0;
|
|
|
|
return {
|
|
value: tag,
|
|
match: match ? match[2] : "",
|
|
closing: match ? !!match[3] : false,
|
|
selfClosing: match ? !!match[5] || match[2] == "/>" : false,
|
|
tagName: match ? match[4] : "",
|
|
column: match[1] ? column + match[1].length : column
|
|
};
|
|
};
|
|
|
|
/**
|
|
* reads a full tag and places the iterator after the tag
|
|
*/
|
|
this._readTagForward = function(iterator) {
|
|
var token = iterator.getCurrentToken();
|
|
if (!token)
|
|
return null;
|
|
|
|
var value = "";
|
|
var start;
|
|
|
|
do {
|
|
if (token.type.indexOf("meta.tag") === 0) {
|
|
if (!start) {
|
|
var start = {
|
|
row: iterator.getCurrentTokenRow(),
|
|
column: iterator.getCurrentTokenColumn()
|
|
};
|
|
}
|
|
value += token.value;
|
|
if (value.indexOf(">") !== -1) {
|
|
var tag = this._parseTag(value);
|
|
tag.start = start;
|
|
tag.end = {
|
|
row: iterator.getCurrentTokenRow(),
|
|
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 value = "";
|
|
var end;
|
|
|
|
do {
|
|
if (token.type.indexOf("meta.tag") === 0) {
|
|
if (!end) {
|
|
end = {
|
|
row: iterator.getCurrentTokenRow(),
|
|
column: iterator.getCurrentTokenColumn() + token.value.length
|
|
};
|
|
}
|
|
value = token.value + value;
|
|
if (value.indexOf("<") !== -1) {
|
|
var tag = this._parseTag(value);
|
|
tag.end = end;
|
|
tag.start = {
|
|
row: iterator.getCurrentTokenRow(),
|
|
column: iterator.getCurrentTokenColumn()
|
|
};
|
|
iterator.stepBackward();
|
|
return tag;
|
|
}
|
|
}
|
|
} 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.voidElements[tag.tagName]) {
|
|
return;
|
|
}
|
|
else if (this.voidElements[top.tagName]) {
|
|
stack.pop();
|
|
continue;
|
|
} else {
|
|
return null;
|
|
}
|
|
}
|
|
};
|
|
|
|
this.getFoldWidgetRange = function(session, foldStyle, row) {
|
|
var firstTag = this._getFirstTagInLine(session, row);
|
|
|
|
if (!firstTag.match)
|
|
return null;
|
|
|
|
var isBackward = firstTag.closing || firstTag.selfClosing;
|
|
var stack = [];
|
|
var tag;
|
|
|
|
if (!isBackward) {
|
|
var iterator = new TokenIterator(session, row, firstTag.column);
|
|
var start = {
|
|
row: row,
|
|
column: firstTag.column + firstTag.tagName.length + 2
|
|
};
|
|
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.column + firstTag.match.length);
|
|
var end = {
|
|
row: row,
|
|
column: firstTag.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;
|
|
return Range.fromPoints(tag.start, end);
|
|
}
|
|
}
|
|
else {
|
|
stack.push(tag)
|
|
}
|
|
}
|
|
}
|
|
|
|
};
|
|
|
|
}).call(FoldMode.prototype);
|
|
|
|
}); |