Permalink
Browse files

Merge remote-tracking branch 'upstream/develop' into develop

  • Loading branch information...
2 parents 202d097 + 2435003 commit 3c3c49e614b66752ec1c812ef194f1aec9b54837 @prauscher committed Apr 7, 2012
View
@@ -56,6 +56,7 @@
, "rjquery.js"
, "AttributePool.js"
, "Changeset.js"
+ , "ChangesetUtils.js"
, "security.js"
, "skiplist.js"
, "virtual_lines.js"
@@ -66,6 +67,7 @@
, "changesettracker.js"
, "linestylefilter.js"
, "domline.js"
+ , "AttributeManager.js"
, "ace2_inner.js"
]
}
@@ -0,0 +1,156 @@
+var Changeset = require('./Changeset');
+var ChangesetUtils = require('./ChangesetUtils');
+var _ = require('./underscore');
+
+var lineMarkerAttribute = 'lmkr';
+
+// If one of these attributes are set to the first character of a
+// line it is considered as a line attribute marker i.e. attributes
+// set on this marker are applied to the whole line.
+// The list attribute is only maintained for compatibility reasons
+var lineAttributes = [lineMarkerAttribute,'list'];
+
+/*
+ The Attribute manager builds changesets based on a document
+ representation for setting and removing range or line-based attributes.
+
+ @param rep the document representation to be used
+ @param applyChangesetCallback this callback will be called
+ once a changeset has been built.
+*/
+
+var AttributeManager = function(rep, applyChangesetCallback)
+{
+ this.rep = rep;
+ this.applyChangesetCallback = applyChangesetCallback;
+ this.author = '';
+
+ // If the first char in a line has one of the following attributes
+ // it will be considered as a line marker
+};
+
+AttributeManager.prototype = _(AttributeManager.prototype).extend({
+
+ applyChangeset: function(changeset){
+ if(!this.applyChangesetCallback) return changeset;
+
+ var cs = changeset.toString();
+ if (!Changeset.isIdentity(cs))
+ {
+ this.applyChangesetCallback(cs);
+ }
+
+ return changeset;
+ },
+
+ /*
+ Sets attributes on a range
+ @param start [row, col] tuple pointing to the start of the range
+ @param end [row, col] tuple pointing to the end of the range
+ @param attribute: an array of attributes
+ */
+ setAttributesOnRange: function(start, end, attribs)
+ {
+ var builder = Changeset.builder(this.rep.lines.totalWidth());
+ ChangesetUtils.buildKeepToStartOfRange(this.rep, builder, start);
+ ChangesetUtils.buildKeepRange(this.rep, builder, start, end, attribs, this.rep.apool);
+ return this.applyChangeset(builder);
+ },
+
+ /*
+ Returns if the line already has a line marker
+ @param lineNum: the number of the line
+ */
+ lineHasMarker: function(lineNum){
+ var that = this;
+
+ return _.find(lineAttributes, function(attribute){
+ return that.getAttributeOnLine(lineNum, attribute) != '';
+ }) !== undefined;
+ },
+
+ /*
+ Gets a specified attribute on a line
+ @param lineNum: the number of the line to set the attribute for
+ @param attributeKey: the name of the attribute to get, e.g. list
+ */
+ getAttributeOnLine: function(lineNum, attributeName){
+ // get `attributeName` attribute of first char of line
+ var aline = this.rep.alines[lineNum];
+ if (aline)
+ {
+ var opIter = Changeset.opIterator(aline);
+ if (opIter.hasNext())
+ {
+ return Changeset.opAttributeValue(opIter.next(), attributeName, this.rep.apool) || '';
+ }
+ }
+ return '';
+ },
+
+ /*
+ Sets a specified attribute on a line
+ @param lineNum: the number of the line to set the attribute for
+ @param attributeKey: the name of the attribute to set, e.g. list
+ @param attributeValue: an optional parameter to pass to the attribute (e.g. indention level)
+
+ */
+ setAttributeOnLine: function(lineNum, attributeName, attributeValue){
+ var loc = [0,0];
+ var builder = Changeset.builder(this.rep.lines.totalWidth());
+ var hasMarker = this.lineHasMarker(lineNum);
+
+ ChangesetUtils.buildKeepRange(this.rep, builder, loc, (loc = [lineNum, 0]));
+
+ if(hasMarker){
+ ChangesetUtils.buildKeepRange(this.rep, builder, loc, (loc = [lineNum, 1]), [
+ [attributeName, attributeValue]
+ ], this.rep.apool);
+ }else{
+ // add a line marker
+ builder.insert('*', [
+ ['author', this.author],
+ ['insertorder', 'first'],
+ [lineMarkerAttribute, '1'],
+ [attributeName, attributeValue]
+ ], this.rep.apool);
+ }
+
+ return this.applyChangeset(builder);
+ },
+
+ /*
+ Removes a specified attribute on a line
+ @param lineNum: the number of the affected line
+ @param attributeKey: the name of the attribute to remove, e.g. list
+
+ */
+ removeAttributeOnLine: function(lineNum, attributeName, attributeValue){
+
+ var loc = [0,0];
+ var builder = Changeset.builder(this.rep.lines.totalWidth());
+ var hasMarker = this.lineHasMarker(lineNum);
+
+ if(hasMarker){
+ ChangesetUtils.buildKeepRange(this.rep, builder, loc, (loc = [lineNum, 0]));
+ ChangesetUtils.buildRemoveRange(this.rep, builder, loc, (loc = [lineNum, 1]));
+ }
+
+ return this.applyChangeset(builder);
+ },
+
+ /*
+ Sets a specified attribute on a line
+ @param lineNum: the number of the line to set the attribute for
+ @param attributeKey: the name of the attribute to set, e.g. list
+ @param attributeValue: an optional parameter to pass to the attribute (e.g. indention level)
+ */
+ toggleAttributeOnLine: function(lineNum, attributeName, attributeValue) {
+ return this.getAttributeOnLine(attributeName) ?
+ this.removeAttributeOnLine(lineNum, attributeName) :
+ this.setAttributeOnLine(lineNum, attributeName, attributeValue);
+
+ }
+});
+
+module.exports = AttributeManager;
@@ -22,6 +22,12 @@
* limitations under the License.
*/
+/*
+ An AttributePool maintains a mapping from [key,value] Pairs called
+ Attributes to Numbers (unsigened integers) and vice versa. These numbers are
+ used to reference Attributes in Changesets.
+*/
+
var AttributePool = function () {
this.numToAttrib = {}; // e.g. {0: ['foo','bar']}
this.attribToNum = {}; // e.g. {'foo,bar': 0}
@@ -0,0 +1,60 @@
+/**
+ * This module contains several helper Functions to build Changesets
+ * based on a SkipList
+ */
+
+/**
+ * Copyright 2009 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS-IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+exports.buildRemoveRange = function(rep, builder, start, end)
+{
+ var startLineOffset = rep.lines.offsetOfIndex(start[0]);
+ var endLineOffset = rep.lines.offsetOfIndex(end[0]);
+
+ if (end[0] > start[0])
+ {
+ builder.remove(endLineOffset - startLineOffset - start[1], end[0] - start[0]);
+ builder.remove(end[1]);
+ }
+ else
+ {
+ builder.remove(end[1] - start[1]);
+ }
+}
+
+exports.buildKeepRange = function(rep, builder, start, end, attribs, pool)
+{
+ var startLineOffset = rep.lines.offsetOfIndex(start[0]);
+ var endLineOffset = rep.lines.offsetOfIndex(end[0]);
+
+ if (end[0] > start[0])
+ {
+ builder.keep(endLineOffset - startLineOffset - start[1], end[0] - start[0], attribs, pool);
+ builder.keep(end[1], 0, attribs, pool);
+ }
+ else
+ {
+ builder.keep(end[1] - start[1], 0, attribs, pool);
+ }
+}
+
+exports.buildKeepToStartOfRange = function(rep, builder, start)
+{
+ var startLineOffset = rep.lines.offsetOfIndex(start[0]);
+
+ builder.keep(startLineOffset, start[0]);
+ builder.keep(start[1]);
+}
+
Oops, something went wrong.

0 comments on commit 3c3c49e

Please sign in to comment.