~elof-bigestans/lenasys/elofsbranch

« back to all changes in this revision

Viewing changes to js/ace/ext-elastic_tabstops_lite.js

  • Committer: Gustav Hartvigsson
  • Date: 2013-04-04 18:10:23 UTC
  • mfrom: (12.2.4 lenasys)
  • Revision ID: gustav.hartvigsson@gmail.com-20130404181023-um5z5jx0jwth4hv9
Merging with implementation group 2's branch, containts an error,
will be fixed. (hopefully).

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
});
 
 
b'\\ No newline at end of file'