/lenasys/trunk

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/lenasys/trunk
15.1.1 by galaxyAbstractor
Started implementation of a new codeviewer using Ace
1
/* ***** BEGIN LICENSE BLOCK *****
2
 * Distributed under the BSD license:
3
 *
4
 * Copyright (c) 2012, Ajax.org B.V.
5
 * All rights reserved.
6
 *
7
 * Redistribution and use in source and binary forms, with or without
8
 * modification, are permitted provided that the following conditions are met:
9
 *     * Redistributions of source code must retain the above copyright
10
 *       notice, this list of conditions and the following disclaimer.
11
 *     * Redistributions in binary form must reproduce the above copyright
12
 *       notice, this list of conditions and the following disclaimer in the
13
 *       documentation and/or other materials provided with the distribution.
14
 *     * Neither the name of Ajax.org B.V. nor the
15
 *       names of its contributors may be used to endorse or promote products
16
 *       derived from this software without specific prior written permission.
17
 *
18
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21
 * DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY
22
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
 *
29
 * ***** END LICENSE BLOCK ***** */
30
31
define('ace/ext/elastic_tabstops_lite', ['require', 'exports', 'module' , 'ace/editor', 'ace/config'], function(require, exports, module) {
32
33
34
var ElasticTabstopsLite = function(editor) {
35
    this.$editor = editor;
36
    var self = this;
37
    var changedRows = [];
38
    var recordChanges = false;
39
    this.onAfterExec = function() {
40
        recordChanges = false;
41
        self.processRows(changedRows);
42
        changedRows = [];
43
    };
44
    this.onExec = function() {
45
        recordChanges = true;
46
    };
47
    this.onChange = function(e) {
48
        var range = e.data.range
49
        if (recordChanges) {
50
            if (changedRows.indexOf(range.start.row) == -1)
51
                changedRows.push(range.start.row);
52
            if (range.end.row != range.start.row)
53
                changedRows.push(range.end.row);
54
        }
55
    };
56
};
57
58
(function() {
59
    this.processRows = function(rows) {
60
        this.$inChange = true;
61
        var checkedRows = [];
62
63
        for (var r = 0, rowCount = rows.length; r < rowCount; r++) {
64
            var row = rows[r];
65
66
            if (checkedRows.indexOf(row) > -1)
67
                continue;
68
69
            var cellWidthObj = this.$findCellWidthsForBlock(row);
70
            var cellWidths = this.$setBlockCellWidthsToMax(cellWidthObj.cellWidths);
71
            var rowIndex = cellWidthObj.firstRow;
72
73
            for (var w = 0, l = cellWidths.length; w < l; w++) {
74
                var widths = cellWidths[w];
75
                checkedRows.push(rowIndex);
76
                this.$adjustRow(rowIndex, widths);
77
                rowIndex++;
78
            }
79
        }
80
        this.$inChange = false;
81
    };
82
83
    this.$findCellWidthsForBlock = function(row) {
84
        var cellWidths = [], widths;
85
        var rowIter = row;
86
        while (rowIter >= 0) {
87
            widths = this.$cellWidthsForRow(rowIter);
88
            if (widths.length == 0)
89
                break;
90
91
            cellWidths.unshift(widths);
92
            rowIter--;
93
        }
94
        var firstRow = rowIter + 1;
95
        rowIter = row;
96
        var numRows = this.$editor.session.getLength();
97
98
        while (rowIter < numRows - 1) {
99
            rowIter++;
100
101
            widths = this.$cellWidthsForRow(rowIter);
102
            if (widths.length == 0)
103
                break;
104
105
            cellWidths.push(widths);
106
        }
107
108
        return { cellWidths: cellWidths, firstRow: firstRow };
109
    };
110
111
    this.$cellWidthsForRow = function(row) {
112
        var selectionColumns = this.$selectionColumnsForRow(row);
113
114
        var tabs = [-1].concat(this.$tabsForRow(row));
115
        var widths = tabs.map(function (el) { return 0; } ).slice(1);
116
        var line = this.$editor.session.getLine(row);
117
118
        for (var i = 0, len = tabs.length - 1; i < len; i++) {
119
            var leftEdge = tabs[i]+1;
120
            var rightEdge = tabs[i+1];
121
122
            var rightmostSelection = this.$rightmostSelectionInCell(selectionColumns, rightEdge);
123
            var cell = line.substring(leftEdge, rightEdge);
124
            widths[i] = Math.max(cell.replace(/\s+$/g,'').length, rightmostSelection - leftEdge);
125
        }
126
        
127
        return widths;
128
    };
129
130
    this.$selectionColumnsForRow = function(row) {
131
        var selections = [], cursor = this.$editor.getCursorPosition();
132
        if (this.$editor.session.getSelection().isEmpty()) {
133
            if (row == cursor.row)
134
                selections.push(cursor.column);   
135
        }
136
137
        return selections;
138
    };
139
140
    this.$setBlockCellWidthsToMax = function(cellWidths) {
141
        var startingNewBlock = true, blockStartRow, blockEndRow, maxWidth;
142
        var columnInfo = this.$izip_longest(cellWidths);
143
144
        for (var c = 0, l = columnInfo.length; c < l; c++) {
145
            var column = columnInfo[c];
146
            if (!column.push) {
147
                console.error(column);
148
                continue;
149
            }
150
            column.push(NaN);
151
152
            for (var r = 0, s = column.length; r < s; r++) {
153
                var width = column[r];
154
                if (startingNewBlock) {
155
                    blockStartRow = r;
156
                    maxWidth = 0;
157
                    startingNewBlock = false;
158
                }
159
                if (isNaN(width)) {
160
                    blockEndRow = r;
161
162
                    for (var j = blockStartRow; j < blockEndRow; j++) {
163
                        cellWidths[j][c] = maxWidth;
164
                    }
165
                    startingNewBlock = true;
166
                }
167
168
                maxWidth = Math.max(maxWidth, width);
169
            }
170
        }
171
172
        return cellWidths;
173
    };
174
175
    this.$rightmostSelectionInCell = function(selectionColumns, cellRightEdge) {
176
        var rightmost = 0;
177
178
        if (selectionColumns.length) {
179
            var lengths = [];
180
            for (var s = 0, length = selectionColumns.length; s < length; s++) {
181
                if (selectionColumns[s] <= cellRightEdge)
182
                    lengths.push(s);
183
                else 
184
                    lengths.push(0);
185
            }
186
            rightmost = Math.max.apply(Math, lengths);
187
        }
188
189
        return rightmost;
190
    };
191
192
    this.$tabsForRow = function(row) {
193
        var rowTabs = [], line = this.$editor.session.getLine(row),
194
            re = /\t/g, match;
195
196
        while ((match = re.exec(line)) != null) {
197
            rowTabs.push(match.index);
198
        }
199
200
        return rowTabs;
201
    };
202
203
    this.$adjustRow = function(row, widths) {
204
        var rowTabs = this.$tabsForRow(row);
205
206
        if (rowTabs.length == 0)
207
            return;
208
        
209
        var bias = 0, location = -1;
210
        var expandedSet = this.$izip(widths, rowTabs);
211
212
        for (var i = 0, l = expandedSet.length; i < l; i++) {
213
            var w = expandedSet[i][0], it = expandedSet[i][1];
214
            location += 1 + w;
215
            it += bias;
216
            var difference = location - it;
217
218
            if (difference == 0)
219
                continue;
220
221
            var partialLine = this.$editor.session.getLine(row).substr(0, it );
222
            var strippedPartialLine = partialLine.replace(/\s*$/g, "");
223
            var ispaces = partialLine.length - strippedPartialLine.length;
224
225
            if (difference > 0) {
226
                this.$editor.session.getDocument().insertInLine({row: row, column: it + 1}, Array(difference + 1).join(" ") + "\t");
227
                this.$editor.session.getDocument().removeInLine(row, it, it + 1);
228
229
                bias += difference;
230
            }
231
232
            if (difference < 0 && ispaces >= -difference) {
233
                this.$editor.session.getDocument().removeInLine(row, it + difference, it);
234
                bias += difference;
235
            }
236
        }
237
    };
238
    this.$izip_longest = function(iterables) {
239
        if (!iterables[0])
240
            return [];
241
        var longest = iterables[0].length;
242
        var iterablesLength = iterables.length;
243
244
        for (var i = 1; i < iterablesLength; i++) {
245
            var iLength = iterables[i].length;
246
            if (iLength > longest)
247
                longest = iLength;
248
        }
249
        
250
        var expandedSet = [];
251
252
        for (var l = 0; l < longest; l++) {
253
            var set = [];
254
            for (var i = 0; i < iterablesLength; i++) {
255
                if (iterables[i][l] === "")
256
                    set.push(NaN);
257
                else
258
                    set.push(iterables[i][l]);
259
            }
260
261
            expandedSet.push(set);
262
        }
263
        
264
265
        return expandedSet;
266
    };
267
    this.$izip = function(widths, tabs) {
268
        var size = widths.length >= tabs.length ? tabs.length : widths.length;
269
        
270
        var expandedSet = [];
271
        for (var i = 0; i < size; i++) {
272
            var set = [ widths[i], tabs[i] ];
273
            expandedSet.push(set);
274
        }
275
        return expandedSet;
276
    };
277
278
}).call(ElasticTabstopsLite.prototype);
279
280
exports.ElasticTabstopsLite = ElasticTabstopsLite;
281
282
var Editor = require("../editor").Editor;
283
require("../config").defineOptions(Editor.prototype, "editor", {
284
    useElasticTabstops: {
285
        set: function(val) {
286
            if (val) {
287
                if (!this.elasticTabstops)
288
                    this.elasticTabstops = new ElasticTabstopsLite(this);
289
                this.commands.on("afterExec", this.elasticTabstops.onAfterExec);
290
                this.commands.on("exec", this.elasticTabstops.onExec);
291
                this.on("change", this.elasticTabstops.onChange);
292
            } else if (this.elasticTabstops) {
293
                this.commands.removeListener("afterExec", this.elasticTabstops.onAfterExec);
294
                this.commands.removeListener("exec", this.elasticTabstops.onExec);
295
                this.removeListener("change", this.elasticTabstops.onChange);
296
            }
297
        }
298
    }
299
});
300
301
});