Projekt

Obecné

Profil

Stáhnout (39.7 KB) Statistiky
| Větev: | Tag: | Revize:
1
ace.define("ace/occur",["require","exports","module","ace/lib/oop","ace/range","ace/search","ace/edit_session","ace/search_highlight","ace/lib/dom"], function(require, exports, module) {
2
"use strict";
3

    
4
var oop = require("./lib/oop");
5
var Range = require("./range").Range;
6
var Search = require("./search").Search;
7
var EditSession = require("./edit_session").EditSession;
8
var SearchHighlight = require("./search_highlight").SearchHighlight;
9
function Occur() {}
10

    
11
oop.inherits(Occur, Search);
12

    
13
(function() {
14
    this.enter = function(editor, options) {
15
        if (!options.needle) return false;
16
        var pos = editor.getCursorPosition();
17
        this.displayOccurContent(editor, options);
18
        var translatedPos = this.originalToOccurPosition(editor.session, pos);
19
        editor.moveCursorToPosition(translatedPos);
20
        return true;
21
    };
22
    this.exit = function(editor, options) {
23
        var pos = options.translatePosition && editor.getCursorPosition();
24
        var translatedPos = pos && this.occurToOriginalPosition(editor.session, pos);
25
        this.displayOriginalContent(editor);
26
        if (translatedPos)
27
            editor.moveCursorToPosition(translatedPos);
28
        return true;
29
    };
30

    
31
    this.highlight = function(sess, regexp) {
32
        var hl = sess.$occurHighlight = sess.$occurHighlight || sess.addDynamicMarker(
33
                new SearchHighlight(null, "ace_occur-highlight", "text"));
34
        hl.setRegexp(regexp);
35
        sess._emit("changeBackMarker"); // force highlight layer redraw
36
    };
37

    
38
    this.displayOccurContent = function(editor, options) {
39
        this.$originalSession = editor.session;
40
        var found = this.matchingLines(editor.session, options);
41
        var lines = found.map(function(foundLine) { return foundLine.content; });
42
        var occurSession = new EditSession(lines.join('\n'));
43
        occurSession.$occur = this;
44
        occurSession.$occurMatchingLines = found;
45
        editor.setSession(occurSession);
46
        this.$useEmacsStyleLineStart = this.$originalSession.$useEmacsStyleLineStart;
47
        occurSession.$useEmacsStyleLineStart = this.$useEmacsStyleLineStart;
48
        this.highlight(occurSession, options.re);
49
        occurSession._emit('changeBackMarker');
50
    };
51

    
52
    this.displayOriginalContent = function(editor) {
53
        editor.setSession(this.$originalSession);
54
        this.$originalSession.$useEmacsStyleLineStart = this.$useEmacsStyleLineStart;
55
    };
56
    this.originalToOccurPosition = function(session, pos) {
57
        var lines = session.$occurMatchingLines;
58
        var nullPos = {row: 0, column: 0};
59
        if (!lines) return nullPos;
60
        for (var i = 0; i < lines.length; i++) {
61
            if (lines[i].row === pos.row)
62
                return {row: i, column: pos.column};
63
        }
64
        return nullPos;
65
    };
66
    this.occurToOriginalPosition = function(session, pos) {
67
        var lines = session.$occurMatchingLines;
68
        if (!lines || !lines[pos.row])
69
            return pos;
70
        return {row: lines[pos.row].row, column: pos.column};
71
    };
72

    
73
    this.matchingLines = function(session, options) {
74
        options = oop.mixin({}, options);
75
        if (!session || !options.needle) return [];
76
        var search = new Search();
77
        search.set(options);
78
        return search.findAll(session).reduce(function(lines, range) {
79
            var row = range.start.row;
80
            var last = lines[lines.length-1];
81
            return last && last.row === row ?
82
                lines :
83
                lines.concat({row: row, content: session.getLine(row)});
84
        }, []);
85
    };
86

    
87
}).call(Occur.prototype);
88

    
89
var dom = require('./lib/dom');
90
dom.importCssString(".ace_occur-highlight {\n\
91
    border-radius: 4px;\n\
92
    background-color: rgba(87, 255, 8, 0.25);\n\
93
    position: absolute;\n\
94
    z-index: 4;\n\
95
    box-sizing: border-box;\n\
96
    box-shadow: 0 0 4px rgb(91, 255, 50);\n\
97
}\n\
98
.ace_dark .ace_occur-highlight {\n\
99
    background-color: rgb(80, 140, 85);\n\
100
    box-shadow: 0 0 4px rgb(60, 120, 70);\n\
101
}\n", "incremental-occur-highlighting");
102

    
103
exports.Occur = Occur;
104

    
105
});
106

    
107
ace.define("ace/commands/occur_commands",["require","exports","module","ace/config","ace/occur","ace/keyboard/hash_handler","ace/lib/oop"], function(require, exports, module) {
108

    
109
var config = require("../config"),
110
    Occur = require("../occur").Occur;
111
var occurStartCommand = {
112
    name: "occur",
113
    exec: function(editor, options) {
114
        var alreadyInOccur = !!editor.session.$occur;
115
        var occurSessionActive = new Occur().enter(editor, options);
116
        if (occurSessionActive && !alreadyInOccur)
117
            OccurKeyboardHandler.installIn(editor);
118
    },
119
    readOnly: true
120
};
121

    
122
var occurCommands = [{
123
    name: "occurexit",
124
    bindKey: 'esc|Ctrl-G',
125
    exec: function(editor) {
126
        var occur = editor.session.$occur;
127
        if (!occur) return;
128
        occur.exit(editor, {});
129
        if (!editor.session.$occur) OccurKeyboardHandler.uninstallFrom(editor);
130
    },
131
    readOnly: true
132
}, {
133
    name: "occuraccept",
134
    bindKey: 'enter',
135
    exec: function(editor) {
136
        var occur = editor.session.$occur;
137
        if (!occur) return;
138
        occur.exit(editor, {translatePosition: true});
139
        if (!editor.session.$occur) OccurKeyboardHandler.uninstallFrom(editor);
140
    },
141
    readOnly: true
142
}];
143

    
144
var HashHandler = require("../keyboard/hash_handler").HashHandler;
145
var oop = require("../lib/oop");
146

    
147

    
148
function OccurKeyboardHandler() {}
149

    
150
oop.inherits(OccurKeyboardHandler, HashHandler);
151

    
152
(function() {
153

    
154
    this.isOccurHandler = true;
155

    
156
    this.attach = function(editor) {
157
        HashHandler.call(this, occurCommands, editor.commands.platform);
158
        this.$editor = editor;
159
    };
160

    
161
    var handleKeyboard$super = this.handleKeyboard;
162
    this.handleKeyboard = function(data, hashId, key, keyCode) {
163
        var cmd = handleKeyboard$super.call(this, data, hashId, key, keyCode);
164
        return (cmd && cmd.command) ? cmd : undefined;
165
    };
166

    
167
}).call(OccurKeyboardHandler.prototype);
168

    
169
OccurKeyboardHandler.installIn = function(editor) {
170
    var handler = new this();
171
    editor.keyBinding.addKeyboardHandler(handler);
172
    editor.commands.addCommands(occurCommands);
173
};
174

    
175
OccurKeyboardHandler.uninstallFrom = function(editor) {
176
    editor.commands.removeCommands(occurCommands);
177
    var handler = editor.getKeyboardHandler();
178
    if (handler.isOccurHandler)
179
        editor.keyBinding.removeKeyboardHandler(handler);
180
};
181

    
182
exports.occurStartCommand = occurStartCommand;
183

    
184
});
185

    
186
ace.define("ace/commands/incremental_search_commands",["require","exports","module","ace/config","ace/lib/oop","ace/keyboard/hash_handler","ace/commands/occur_commands"], function(require, exports, module) {
187

    
188
var config = require("../config");
189
var oop = require("../lib/oop");
190
var HashHandler = require("../keyboard/hash_handler").HashHandler;
191
var occurStartCommand = require("./occur_commands").occurStartCommand;
192
exports.iSearchStartCommands = [{
193
    name: "iSearch",
194
    bindKey: {win: "Ctrl-F", mac: "Command-F"},
195
    exec: function(editor, options) {
196
        config.loadModule(["core", "ace/incremental_search"], function(e) {
197
            var iSearch = e.iSearch = e.iSearch || new e.IncrementalSearch();
198
            iSearch.activate(editor, options.backwards);
199
            if (options.jumpToFirstMatch) iSearch.next(options);
200
        });
201
    },
202
    readOnly: true
203
}, {
204
    name: "iSearchBackwards",
205
    exec: function(editor, jumpToNext) { editor.execCommand('iSearch', {backwards: true}); },
206
    readOnly: true
207
}, {
208
    name: "iSearchAndGo",
209
    bindKey: {win: "Ctrl-K", mac: "Command-G"},
210
    exec: function(editor, jumpToNext) { editor.execCommand('iSearch', {jumpToFirstMatch: true, useCurrentOrPrevSearch: true}); },
211
    readOnly: true
212
}, {
213
    name: "iSearchBackwardsAndGo",
214
    bindKey: {win: "Ctrl-Shift-K", mac: "Command-Shift-G"},
215
    exec: function(editor) { editor.execCommand('iSearch', {jumpToFirstMatch: true, backwards: true, useCurrentOrPrevSearch: true}); },
216
    readOnly: true
217
}];
218
exports.iSearchCommands = [{
219
    name: "restartSearch",
220
    bindKey: {win: "Ctrl-F", mac: "Command-F"},
221
    exec: function(iSearch) {
222
        iSearch.cancelSearch(true);
223
    }
224
}, {
225
    name: "searchForward",
226
    bindKey: {win: "Ctrl-S|Ctrl-K", mac: "Ctrl-S|Command-G"},
227
    exec: function(iSearch, options) {
228
        options.useCurrentOrPrevSearch = true;
229
        iSearch.next(options);
230
    }
231
}, {
232
    name: "searchBackward",
233
    bindKey: {win: "Ctrl-R|Ctrl-Shift-K", mac: "Ctrl-R|Command-Shift-G"},
234
    exec: function(iSearch, options) {
235
        options.useCurrentOrPrevSearch = true;
236
        options.backwards = true;
237
        iSearch.next(options);
238
    }
239
}, {
240
    name: "extendSearchTerm",
241
    exec: function(iSearch, string) {
242
        iSearch.addString(string);
243
    }
244
}, {
245
    name: "extendSearchTermSpace",
246
    bindKey: "space",
247
    exec: function(iSearch) { iSearch.addString(' '); }
248
}, {
249
    name: "shrinkSearchTerm",
250
    bindKey: "backspace",
251
    exec: function(iSearch) {
252
        iSearch.removeChar();
253
    }
254
}, {
255
    name: 'confirmSearch',
256
    bindKey: 'return',
257
    exec: function(iSearch) { iSearch.deactivate(); }
258
}, {
259
    name: 'cancelSearch',
260
    bindKey: 'esc|Ctrl-G',
261
    exec: function(iSearch) { iSearch.deactivate(true); }
262
}, {
263
    name: 'occurisearch',
264
    bindKey: 'Ctrl-O',
265
    exec: function(iSearch) {
266
        var options = oop.mixin({}, iSearch.$options);
267
        iSearch.deactivate();
268
        occurStartCommand.exec(iSearch.$editor, options);
269
    }
270
}, {
271
    name: "yankNextWord",
272
    bindKey: "Ctrl-w",
273
    exec: function(iSearch) {
274
        var ed = iSearch.$editor,
275
            range = ed.selection.getRangeOfMovements(function(sel) { sel.moveCursorWordRight(); }),
276
            string = ed.session.getTextRange(range);
277
        iSearch.addString(string);
278
    }
279
}, {
280
    name: "yankNextChar",
281
    bindKey: "Ctrl-Alt-y",
282
    exec: function(iSearch) {
283
        var ed = iSearch.$editor,
284
            range = ed.selection.getRangeOfMovements(function(sel) { sel.moveCursorRight(); }),
285
            string = ed.session.getTextRange(range);
286
        iSearch.addString(string);
287
    }
288
}, {
289
    name: 'recenterTopBottom',
290
    bindKey: 'Ctrl-l',
291
    exec: function(iSearch) { iSearch.$editor.execCommand('recenterTopBottom'); }
292
}, {
293
    name: 'selectAllMatches',
294
    bindKey: 'Ctrl-space',
295
    exec: function(iSearch) {
296
        var ed = iSearch.$editor,
297
            hl = ed.session.$isearchHighlight,
298
            ranges = hl && hl.cache ? hl.cache
299
                .reduce(function(ranges, ea) {
300
                    return ranges.concat(ea ? ea : []); }, []) : [];
301
        iSearch.deactivate(false);
302
        ranges.forEach(ed.selection.addRange.bind(ed.selection));
303
    }
304
}, {
305
    name: 'searchAsRegExp',
306
    bindKey: 'Alt-r',
307
    exec: function(iSearch) {
308
        iSearch.convertNeedleToRegExp();
309
    }
310
}].map(function(cmd) {
311
    cmd.readOnly = true;
312
    cmd.isIncrementalSearchCommand = true;
313
    cmd.scrollIntoView = "animate-cursor";
314
    return cmd;
315
});
316

    
317
function IncrementalSearchKeyboardHandler(iSearch) {
318
    this.$iSearch = iSearch;
319
}
320

    
321
oop.inherits(IncrementalSearchKeyboardHandler, HashHandler);
322

    
323
(function() {
324

    
325
    this.attach = function(editor) {
326
        var iSearch = this.$iSearch;
327
        HashHandler.call(this, exports.iSearchCommands, editor.commands.platform);
328
        this.$commandExecHandler = editor.commands.on('exec', function(e) {
329
            if (!e.command.isIncrementalSearchCommand)
330
                return iSearch.deactivate();
331
            e.stopPropagation();
332
            e.preventDefault();
333
            var scrollTop = editor.session.getScrollTop();
334
            var result = e.command.exec(iSearch, e.args || {});
335
            editor.renderer.scrollCursorIntoView(null, 0.5);
336
            editor.renderer.animateScrolling(scrollTop);
337
            return result;
338
        });
339
    };
340

    
341
    this.detach = function(editor) {
342
        if (!this.$commandExecHandler) return;
343
        editor.commands.off('exec', this.$commandExecHandler);
344
        delete this.$commandExecHandler;
345
    };
346

    
347
    var handleKeyboard$super = this.handleKeyboard;
348
    this.handleKeyboard = function(data, hashId, key, keyCode) {
349
        if (((hashId === 1/*ctrl*/ || hashId === 8/*command*/) && key === 'v')
350
         || (hashId === 1/*ctrl*/ && key === 'y')) return null;
351
        var cmd = handleKeyboard$super.call(this, data, hashId, key, keyCode);
352
        if (cmd && cmd.command) { return cmd; }
353
        if (hashId == -1) {
354
            var extendCmd = this.commands.extendSearchTerm;
355
            if (extendCmd) { return {command: extendCmd, args: key}; }
356
        }
357
        return false;
358
    };
359

    
360
}).call(IncrementalSearchKeyboardHandler.prototype);
361

    
362

    
363
exports.IncrementalSearchKeyboardHandler = IncrementalSearchKeyboardHandler;
364

    
365
});
366

    
367
ace.define("ace/incremental_search",["require","exports","module","ace/lib/oop","ace/range","ace/search","ace/search_highlight","ace/commands/incremental_search_commands","ace/lib/dom","ace/commands/command_manager","ace/editor","ace/config"], function(require, exports, module) {
368
"use strict";
369

    
370
var oop = require("./lib/oop");
371
var Range = require("./range").Range;
372
var Search = require("./search").Search;
373
var SearchHighlight = require("./search_highlight").SearchHighlight;
374
var iSearchCommandModule = require("./commands/incremental_search_commands");
375
var ISearchKbd = iSearchCommandModule.IncrementalSearchKeyboardHandler;
376
function IncrementalSearch() {
377
    this.$options = {wrap: false, skipCurrent: false};
378
    this.$keyboardHandler = new ISearchKbd(this);
379
}
380

    
381
oop.inherits(IncrementalSearch, Search);
382

    
383
function isRegExp(obj) {
384
    return obj instanceof RegExp;
385
}
386

    
387
function regExpToObject(re) {
388
    var string = String(re),
389
        start = string.indexOf('/'),
390
        flagStart = string.lastIndexOf('/');
391
    return {
392
        expression: string.slice(start+1, flagStart),
393
        flags: string.slice(flagStart+1)
394
    };
395
}
396

    
397
function stringToRegExp(string, flags) {
398
    try {
399
        return new RegExp(string, flags);
400
    } catch (e) { return string; }
401
}
402

    
403
function objectToRegExp(obj) {
404
    return stringToRegExp(obj.expression, obj.flags);
405
}
406

    
407
(function() {
408

    
409
    this.activate = function(editor, backwards) {
410
        this.$editor = editor;
411
        this.$startPos = this.$currentPos = editor.getCursorPosition();
412
        this.$options.needle = '';
413
        this.$options.backwards = backwards;
414
        editor.keyBinding.addKeyboardHandler(this.$keyboardHandler);
415
        this.$originalEditorOnPaste = editor.onPaste; 
416
        editor.onPaste = this.onPaste.bind(this);
417
        this.$mousedownHandler = editor.on('mousedown', this.onMouseDown.bind(this));
418
        this.selectionFix(editor);
419
        this.statusMessage(true);
420
    };
421

    
422
    this.deactivate = function(reset) {
423
        this.cancelSearch(reset);
424
        var editor = this.$editor;
425
        editor.keyBinding.removeKeyboardHandler(this.$keyboardHandler);
426
        if (this.$mousedownHandler) {
427
            editor.off('mousedown', this.$mousedownHandler);
428
            delete this.$mousedownHandler;
429
        }
430
        editor.onPaste = this.$originalEditorOnPaste;
431
        this.message('');
432
    };
433

    
434
    this.selectionFix = function(editor) {
435
        if (editor.selection.isEmpty() && !editor.session.$emacsMark) {
436
            editor.clearSelection();
437
        }
438
    };
439

    
440
    this.highlight = function(regexp) {
441
        var sess = this.$editor.session,
442
            hl = sess.$isearchHighlight = sess.$isearchHighlight || sess.addDynamicMarker(
443
                new SearchHighlight(null, "ace_isearch-result", "text"));
444
        hl.setRegexp(regexp);
445
        sess._emit("changeBackMarker"); // force highlight layer redraw
446
    };
447

    
448
    this.cancelSearch = function(reset) {
449
        var e = this.$editor;
450
        this.$prevNeedle = this.$options.needle;
451
        this.$options.needle = '';
452
        if (reset) {
453
            e.moveCursorToPosition(this.$startPos);
454
            this.$currentPos = this.$startPos;
455
        } else {
456
            e.pushEmacsMark && e.pushEmacsMark(this.$startPos, false);
457
        }
458
        this.highlight(null);
459
        return Range.fromPoints(this.$currentPos, this.$currentPos);
460
    };
461

    
462
    this.highlightAndFindWithNeedle = function(moveToNext, needleUpdateFunc) {
463
        if (!this.$editor) return null;
464
        var options = this.$options;
465
        if (needleUpdateFunc) {
466
            options.needle = needleUpdateFunc.call(this, options.needle || '') || '';
467
        }
468
        if (options.needle.length === 0) {
469
            this.statusMessage(true);
470
            return this.cancelSearch(true);
471
        }
472
        options.start = this.$currentPos;
473
        var session = this.$editor.session,
474
            found = this.find(session),
475
            shouldSelect = this.$editor.emacsMark ?
476
                !!this.$editor.emacsMark() : !this.$editor.selection.isEmpty();
477
        if (found) {
478
            if (options.backwards) found = Range.fromPoints(found.end, found.start);
479
            this.$editor.selection.setRange(Range.fromPoints(shouldSelect ? this.$startPos : found.end, found.end));
480
            if (moveToNext) this.$currentPos = found.end;
481
            this.highlight(options.re);
482
        }
483

    
484
        this.statusMessage(found);
485

    
486
        return found;
487
    };
488

    
489
    this.addString = function(s) {
490
        return this.highlightAndFindWithNeedle(false, function(needle) {
491
            if (!isRegExp(needle))
492
              return needle + s;
493
            var reObj = regExpToObject(needle);
494
            reObj.expression += s;
495
            return objectToRegExp(reObj);
496
        });
497
    };
498

    
499
    this.removeChar = function(c) {
500
        return this.highlightAndFindWithNeedle(false, function(needle) {
501
            if (!isRegExp(needle))
502
              return needle.substring(0, needle.length-1);
503
            var reObj = regExpToObject(needle);
504
            reObj.expression = reObj.expression.substring(0, reObj.expression.length-1);
505
            return objectToRegExp(reObj);
506
        });
507
    };
508

    
509
    this.next = function(options) {
510
        options = options || {};
511
        this.$options.backwards = !!options.backwards;
512
        this.$currentPos = this.$editor.getCursorPosition();
513
        return this.highlightAndFindWithNeedle(true, function(needle) {
514
            return options.useCurrentOrPrevSearch && needle.length === 0 ?
515
                this.$prevNeedle || '' : needle;
516
        });
517
    };
518

    
519
    this.onMouseDown = function(evt) {
520
        this.deactivate();
521
        return true;
522
    };
523

    
524
    this.onPaste = function(text) {
525
        this.addString(text);
526
    };
527

    
528
    this.convertNeedleToRegExp = function() {
529
        return this.highlightAndFindWithNeedle(false, function(needle) {
530
            return isRegExp(needle) ? needle : stringToRegExp(needle, 'ig');
531
        });
532
    };
533

    
534
    this.convertNeedleToString = function() {
535
        return this.highlightAndFindWithNeedle(false, function(needle) {
536
            return isRegExp(needle) ? regExpToObject(needle).expression : needle;
537
        });
538
    };
539

    
540
    this.statusMessage = function(found) {
541
        var options = this.$options, msg = '';
542
        msg += options.backwards ? 'reverse-' : '';
543
        msg += 'isearch: ' + options.needle;
544
        msg += found ? '' : ' (not found)';
545
        this.message(msg);
546
    };
547

    
548
    this.message = function(msg) {
549
        if (this.$editor.showCommandLine) {
550
            this.$editor.showCommandLine(msg);
551
            this.$editor.focus();
552
        }
553
    };
554

    
555
}).call(IncrementalSearch.prototype);
556

    
557

    
558
exports.IncrementalSearch = IncrementalSearch;
559

    
560
var dom = require('./lib/dom');
561
dom.importCssString && dom.importCssString("\
562
.ace_marker-layer .ace_isearch-result {\
563
  position: absolute;\
564
  z-index: 6;\
565
  box-sizing: border-box;\
566
}\
567
div.ace_isearch-result {\
568
  border-radius: 4px;\
569
  background-color: rgba(255, 200, 0, 0.5);\
570
  box-shadow: 0 0 4px rgb(255, 200, 0);\
571
}\
572
.ace_dark div.ace_isearch-result {\
573
  background-color: rgb(100, 110, 160);\
574
  box-shadow: 0 0 4px rgb(80, 90, 140);\
575
}", "incremental-search-highlighting");
576
var commands = require("./commands/command_manager");
577
(function() {
578
    this.setupIncrementalSearch = function(editor, val) {
579
        if (this.usesIncrementalSearch == val) return;
580
        this.usesIncrementalSearch = val;
581
        var iSearchCommands = iSearchCommandModule.iSearchStartCommands;
582
        var method = val ? 'addCommands' : 'removeCommands';
583
        this[method](iSearchCommands);
584
    };
585
}).call(commands.CommandManager.prototype);
586
var Editor = require("./editor").Editor;
587
require("./config").defineOptions(Editor.prototype, "editor", {
588
    useIncrementalSearch: {
589
        set: function(val) {
590
            this.keyBinding.$handlers.forEach(function(handler) {
591
                if (handler.setupIncrementalSearch) {
592
                    handler.setupIncrementalSearch(this, val);
593
                }
594
            });
595
            this._emit('incrementalSearchSettingChanged', {isEnabled: val});
596
        }
597
    }
598
});
599

    
600
});
601

    
602
ace.define("ace/keyboard/emacs",["require","exports","module","ace/lib/dom","ace/incremental_search","ace/commands/incremental_search_commands","ace/keyboard/hash_handler","ace/lib/keys"], function(require, exports, module) {
603
"use strict";
604

    
605
var dom = require("../lib/dom");
606
require("../incremental_search");
607
var iSearchCommandModule = require("../commands/incremental_search_commands");
608

    
609

    
610
var HashHandler = require("./hash_handler").HashHandler;
611
exports.handler = new HashHandler();
612

    
613
exports.handler.isEmacs = true;
614
exports.handler.$id = "ace/keyboard/emacs";
615

    
616
var initialized = false;
617
var $formerLongWords;
618
var $formerLineStart;
619

    
620
exports.handler.attach = function(editor) {
621
    if (!initialized) {
622
        initialized = true;
623
        dom.importCssString('\
624
            .emacs-mode .ace_cursor{\
625
                border: 1px rgba(50,250,50,0.8) solid!important;\
626
                box-sizing: border-box!important;\
627
                background-color: rgba(0,250,0,0.9);\
628
                opacity: 0.5;\
629
            }\
630
            .emacs-mode .ace_hidden-cursors .ace_cursor{\
631
                opacity: 1;\
632
                background-color: transparent;\
633
            }\
634
            .emacs-mode .ace_overwrite-cursors .ace_cursor {\
635
                opacity: 1;\
636
                background-color: transparent;\
637
                border-width: 0 0 2px 2px !important;\
638
            }\
639
            .emacs-mode .ace_text-layer {\
640
                z-index: 4\
641
            }\
642
            .emacs-mode .ace_cursor-layer {\
643
                z-index: 2\
644
            }', 'emacsMode'
645
        );
646
    }
647
    $formerLongWords = editor.session.$selectLongWords;
648
    editor.session.$selectLongWords = true;
649
    $formerLineStart = editor.session.$useEmacsStyleLineStart;
650
    editor.session.$useEmacsStyleLineStart = true;
651

    
652
    editor.session.$emacsMark = null; // the active mark
653
    editor.session.$emacsMarkRing = editor.session.$emacsMarkRing || [];
654

    
655
    editor.emacsMark = function() {
656
        return this.session.$emacsMark;
657
    };
658

    
659
    editor.setEmacsMark = function(p) {
660
        this.session.$emacsMark = p;
661
    };
662

    
663
    editor.pushEmacsMark = function(p, activate) {
664
        var prevMark = this.session.$emacsMark;
665
        if (prevMark)
666
            this.session.$emacsMarkRing.push(prevMark);
667
        if (!p || activate) this.setEmacsMark(p);
668
        else this.session.$emacsMarkRing.push(p);
669
    };
670

    
671
    editor.popEmacsMark = function() {
672
        var mark = this.emacsMark();
673
        if (mark) { this.setEmacsMark(null); return mark; }
674
        return this.session.$emacsMarkRing.pop();
675
    };
676

    
677
    editor.getLastEmacsMark = function(p) {
678
        return this.session.$emacsMark || this.session.$emacsMarkRing.slice(-1)[0];
679
    };
680

    
681
    editor.emacsMarkForSelection = function(replacement) {
682
        var sel = this.selection,
683
            multiRangeLength = this.multiSelect ?
684
                this.multiSelect.getAllRanges().length : 1,
685
            selIndex = sel.index || 0,
686
            markRing = this.session.$emacsMarkRing,
687
            markIndex = markRing.length - (multiRangeLength - selIndex),
688
            lastMark = markRing[markIndex] || sel.anchor;
689
        if (replacement) {
690
            markRing.splice(markIndex, 1,
691
                "row" in replacement && "column" in replacement ?
692
                    replacement : undefined);
693
        }
694
        return lastMark;
695
    };
696

    
697
    editor.on("click", $resetMarkMode);
698
    editor.on("changeSession", $kbSessionChange);
699
    editor.renderer.$blockCursor = true;
700
    editor.setStyle("emacs-mode");
701
    editor.commands.addCommands(commands);
702
    exports.handler.platform = editor.commands.platform;
703
    editor.$emacsModeHandler = this;
704
    editor.on('copy', this.onCopy);
705
    editor.on('paste', this.onPaste);
706
};
707

    
708
exports.handler.detach = function(editor) {
709
    editor.renderer.$blockCursor = false;
710
    editor.session.$selectLongWords = $formerLongWords;
711
    editor.session.$useEmacsStyleLineStart = $formerLineStart;
712
    editor.off("click", $resetMarkMode);
713
    editor.off("changeSession", $kbSessionChange);
714
    editor.unsetStyle("emacs-mode");
715
    editor.commands.removeCommands(commands);
716
    editor.off('copy', this.onCopy);
717
    editor.off('paste', this.onPaste);
718
    editor.$emacsModeHandler = null;
719
};
720

    
721
var $kbSessionChange = function(e) {
722
    if (e.oldSession) {
723
        e.oldSession.$selectLongWords = $formerLongWords;
724
        e.oldSession.$useEmacsStyleLineStart = $formerLineStart;
725
    }
726

    
727
    $formerLongWords = e.session.$selectLongWords;
728
    e.session.$selectLongWords = true;
729
    $formerLineStart = e.session.$useEmacsStyleLineStart;
730
    e.session.$useEmacsStyleLineStart = true;
731

    
732
    if (!e.session.hasOwnProperty('$emacsMark'))
733
        e.session.$emacsMark = null;
734
    if (!e.session.hasOwnProperty('$emacsMarkRing'))
735
        e.session.$emacsMarkRing = [];
736
};
737

    
738
var $resetMarkMode = function(e) {
739
    e.editor.session.$emacsMark = null;
740
};
741

    
742
var keys = require("../lib/keys").KEY_MODS;
743
var eMods = {C: "ctrl", S: "shift", M: "alt", CMD: "command"};
744
var combinations = ["C-S-M-CMD",
745
                    "S-M-CMD", "C-M-CMD", "C-S-CMD", "C-S-M",
746
                    "M-CMD", "S-CMD", "S-M", "C-CMD", "C-M", "C-S",
747
                    "CMD", "M", "S", "C"];
748
combinations.forEach(function(c) {
749
    var hashId = 0;
750
    c.split("-").forEach(function(c) {
751
        hashId = hashId | keys[eMods[c]];
752
    });
753
    eMods[hashId] = c.toLowerCase() + "-";
754
});
755

    
756
exports.handler.onCopy = function(e, editor) {
757
    if (editor.$handlesEmacsOnCopy) return;
758
    editor.$handlesEmacsOnCopy = true;
759
    exports.handler.commands.killRingSave.exec(editor);
760
    editor.$handlesEmacsOnCopy = false;
761
};
762

    
763
exports.handler.onPaste = function(e, editor) {
764
    editor.pushEmacsMark(editor.getCursorPosition());
765
};
766

    
767
exports.handler.bindKey = function(key, command) {
768
    if (typeof key == "object")
769
        key = key[this.platform];
770
    if (!key)
771
        return;
772

    
773
    var ckb = this.commandKeyBinding;
774
    key.split("|").forEach(function(keyPart) {
775
        keyPart = keyPart.toLowerCase();
776
        ckb[keyPart] = command;
777
        var keyParts = keyPart.split(" ").slice(0,-1);
778
        keyParts.reduce(function(keyMapKeys, keyPart, i) {
779
            var prefix = keyMapKeys[i-1] ? keyMapKeys[i-1] + ' ' : '';
780
            return keyMapKeys.concat([prefix + keyPart]);
781
        }, []).forEach(function(keyPart) {
782
            if (!ckb[keyPart]) ckb[keyPart] = "null";
783
        });
784
    }, this);
785
};
786

    
787
exports.handler.getStatusText = function(editor, data) {
788
  var str = "";
789
  if (data.count)
790
    str += data.count;
791
  if (data.keyChain)
792
    str += " " + data.keyChain;
793
  return str;
794
};
795

    
796
exports.handler.handleKeyboard = function(data, hashId, key, keyCode) {
797
    if (keyCode === -1) return undefined;
798

    
799
    var editor = data.editor;
800
    editor._signal("changeStatus");
801
    if (hashId == -1) {
802
        editor.pushEmacsMark();
803
        if (data.count) {
804
            var str = new Array(data.count + 1).join(key);
805
            data.count = null;
806
            return {command: "insertstring", args: str};
807
        }
808
    }
809

    
810
    var modifier = eMods[hashId];
811
    if (modifier == "c-" || data.count) {
812
        var count = parseInt(key[key.length - 1]);
813
        if (typeof count === 'number' && !isNaN(count)) {
814
            data.count = Math.max(data.count, 0) || 0;
815
            data.count = 10 * data.count + count;
816
            return {command: "null"};
817
        }
818
    }
819
    if (modifier) key = modifier + key;
820
    if (data.keyChain) key = data.keyChain += " " + key;
821
    var command = this.commandKeyBinding[key];
822
    data.keyChain = command == "null" ? key : "";
823
    if (!command) return undefined;
824
    if (command === "null") return {command: "null"};
825

    
826
    if (command === "universalArgument") {
827
        data.count = -4;
828
        return {command: "null"};
829
    }
830
    var args;
831
    if (typeof command !== "string") {
832
        args = command.args;
833
        if (command.command) command = command.command;
834
        if (command === "goorselect") {
835
            command = editor.emacsMark() ? args[1] : args[0];
836
            args = null;
837
        }
838
    }
839

    
840
    if (typeof command === "string") {
841
        if (command === "insertstring" ||
842
            command === "splitline" ||
843
            command === "togglecomment") {
844
            editor.pushEmacsMark();
845
        }
846
        command = this.commands[command] || editor.commands.commands[command];
847
        if (!command) return undefined;
848
    }
849

    
850
    if (!command.readOnly && !command.isYank)
851
        data.lastCommand = null;
852

    
853
    if (!command.readOnly && editor.emacsMark())
854
        editor.setEmacsMark(null);
855
        
856
    if (data.count) {
857
        var count = data.count;
858
        data.count = 0;
859
        if (!command || !command.handlesCount) {
860
            return {
861
                args: args,
862
                command: {
863
                    exec: function(editor, args) {
864
                        for (var i = 0; i < count; i++)
865
                            command.exec(editor, args);
866
                    },
867
                    multiSelectAction: command.multiSelectAction
868
                }
869
            };
870
        } else {
871
            if (!args) args = {};
872
            if (typeof args === 'object') args.count = count;
873
        }
874
    }
875

    
876
    return {command: command, args: args};
877
};
878

    
879
exports.emacsKeys = {
880
    "Up|C-p"      : {command: "goorselect", args: ["golineup","selectup"]},
881
    "Down|C-n"    : {command: "goorselect", args: ["golinedown","selectdown"]},
882
    "Left|C-b"    : {command: "goorselect", args: ["gotoleft","selectleft"]},
883
    "Right|C-f"   : {command: "goorselect", args: ["gotoright","selectright"]},
884
    "C-Left|M-b"  : {command: "goorselect", args: ["gotowordleft","selectwordleft"]},
885
    "C-Right|M-f" : {command: "goorselect", args: ["gotowordright","selectwordright"]},
886
    "Home|C-a"    : {command: "goorselect", args: ["gotolinestart","selecttolinestart"]},
887
    "End|C-e"     : {command: "goorselect", args: ["gotolineend","selecttolineend"]},
888
    "C-Home|S-M-,": {command: "goorselect", args: ["gotostart","selecttostart"]},
889
    "C-End|S-M-." : {command: "goorselect", args: ["gotoend","selecttoend"]},
890
    "S-Up|S-C-p"      : "selectup",
891
    "S-Down|S-C-n"    : "selectdown",
892
    "S-Left|S-C-b"    : "selectleft",
893
    "S-Right|S-C-f"   : "selectright",
894
    "S-C-Left|S-M-b"  : "selectwordleft",
895
    "S-C-Right|S-M-f" : "selectwordright",
896
    "S-Home|S-C-a"    : "selecttolinestart",
897
    "S-End|S-C-e"     : "selecttolineend",
898
    "S-C-Home"        : "selecttostart",
899
    "S-C-End"         : "selecttoend",
900

    
901
    "C-l" : "recenterTopBottom",
902
    "M-s" : "centerselection",
903
    "M-g": "gotoline",
904
    "C-x C-p": "selectall",
905
    "C-Down": {command: "goorselect", args: ["gotopagedown","selectpagedown"]},
906
    "C-Up": {command: "goorselect", args: ["gotopageup","selectpageup"]},
907
    "PageDown|C-v": {command: "goorselect", args: ["gotopagedown","selectpagedown"]},
908
    "PageUp|M-v": {command: "goorselect", args: ["gotopageup","selectpageup"]},
909
    "S-C-Down": "selectpagedown",
910
    "S-C-Up": "selectpageup",
911

    
912
    "C-s": "iSearch",
913
    "C-r": "iSearchBackwards",
914

    
915
    "M-C-s": "findnext",
916
    "M-C-r": "findprevious",
917
    "S-M-5": "replace",
918
    "Backspace": "backspace",
919
    "Delete|C-d": "del",
920
    "Return|C-m": {command: "insertstring", args: "\n"}, // "newline"
921
    "C-o": "splitline",
922

    
923
    "M-d|C-Delete": {command: "killWord", args: "right"},
924
    "C-Backspace|M-Backspace|M-Delete": {command: "killWord", args: "left"},
925
    "C-k": "killLine",
926

    
927
    "C-y|S-Delete": "yank",
928
    "M-y": "yankRotate",
929
    "C-g": "keyboardQuit",
930

    
931
    "C-w|C-S-W": "killRegion",
932
    "M-w": "killRingSave",
933
    "C-Space": "setMark",
934
    "C-x C-x": "exchangePointAndMark",
935

    
936
    "C-t": "transposeletters",
937
    "M-u": "touppercase",    // Doesn't work
938
    "M-l": "tolowercase",
939
    "M-/": "autocomplete",   // Doesn't work
940
    "C-u": "universalArgument",
941

    
942
    "M-;": "togglecomment",
943

    
944
    "C-/|C-x u|S-C--|C-z": "undo",
945
    "S-C-/|S-C-x u|C--|S-C-z": "redo", // infinite undo?
946
    "C-x r":  "selectRectangularRegion",
947
    "M-x": {command: "focusCommandLine", args: "M-x "}
948
};
949

    
950

    
951
exports.handler.bindKeys(exports.emacsKeys);
952

    
953
exports.handler.addCommands({
954
    recenterTopBottom: function(editor) {
955
        var renderer = editor.renderer;
956
        var pos = renderer.$cursorLayer.getPixelPosition();
957
        var h = renderer.$size.scrollerHeight - renderer.lineHeight;
958
        var scrollTop = renderer.scrollTop;
959
        if (Math.abs(pos.top - scrollTop) < 2) {
960
            scrollTop = pos.top - h;
961
        } else if (Math.abs(pos.top - scrollTop - h * 0.5) < 2) {
962
            scrollTop = pos.top;
963
        } else {
964
            scrollTop = pos.top - h * 0.5;
965
        }
966
        editor.session.setScrollTop(scrollTop);
967
    },
968
    selectRectangularRegion:  function(editor) {
969
        editor.multiSelect.toggleBlockSelection();
970
    },
971
    setMark:  {
972
        exec: function(editor, args) {
973

    
974
            if (args && args.count) {
975
                if (editor.inMultiSelectMode) editor.forEachSelection(moveToMark);
976
                else moveToMark();
977
                moveToMark();
978
                return;
979
            }
980

    
981
            var mark = editor.emacsMark(),
982
                ranges = editor.selection.getAllRanges(),
983
                rangePositions = ranges.map(function(r) { return {row: r.start.row, column: r.start.column}; }),
984
                transientMarkModeActive = true,
985
                hasNoSelection = ranges.every(function(range) { return range.isEmpty(); });
986
            if (transientMarkModeActive && (mark || !hasNoSelection)) {
987
                if (editor.inMultiSelectMode) editor.forEachSelection({exec: editor.clearSelection.bind(editor)});
988
                else editor.clearSelection();
989
                if (mark) editor.pushEmacsMark(null);
990
                return;
991
            }
992

    
993
            if (!mark) {
994
                rangePositions.forEach(function(pos) { editor.pushEmacsMark(pos); });
995
                editor.setEmacsMark(rangePositions[rangePositions.length-1]);
996
                return;
997
            }
998

    
999
            function moveToMark() {
1000
                var mark = editor.popEmacsMark();
1001
                mark && editor.moveCursorToPosition(mark);
1002
            }
1003

    
1004
        },
1005
        readOnly: true,
1006
        handlesCount: true
1007
    },
1008
    exchangePointAndMark: {
1009
        exec: function exchangePointAndMark$exec(editor, args) {
1010
            var sel = editor.selection;
1011
            if (!args.count && !sel.isEmpty()) { // just invert selection
1012
                sel.setSelectionRange(sel.getRange(), !sel.isBackwards());
1013
                return;
1014
            }
1015

    
1016
            if (args.count) { // replace mark and point
1017
                var pos = {row: sel.lead.row, column: sel.lead.column};
1018
                sel.clearSelection();
1019
                sel.moveCursorToPosition(editor.emacsMarkForSelection(pos));
1020
            } else { // create selection to last mark
1021
                sel.selectToPosition(editor.emacsMarkForSelection());
1022
            }
1023
        },
1024
        readOnly: true,
1025
        handlesCount: true,
1026
        multiSelectAction: "forEach"
1027
    },
1028
    killWord: {
1029
        exec: function(editor, dir) {
1030
            editor.clearSelection();
1031
            if (dir == "left")
1032
                editor.selection.selectWordLeft();
1033
            else
1034
                editor.selection.selectWordRight();
1035

    
1036
            var range = editor.getSelectionRange();
1037
            var text = editor.session.getTextRange(range);
1038
            exports.killRing.add(text);
1039

    
1040
            editor.session.remove(range);
1041
            editor.clearSelection();
1042
        },
1043
        multiSelectAction: "forEach"
1044
    },
1045
    killLine: function(editor) {
1046
        editor.pushEmacsMark(null);
1047
        editor.clearSelection();
1048
        var range = editor.getSelectionRange();
1049
        var line = editor.session.getLine(range.start.row);
1050
        range.end.column = line.length;
1051
        line = line.substr(range.start.column);
1052
        
1053
        var foldLine = editor.session.getFoldLine(range.start.row);
1054
        if (foldLine && range.end.row != foldLine.end.row) {
1055
            range.end.row = foldLine.end.row;
1056
            line = "x";
1057
        }
1058
        if (/^\s*$/.test(line)) {
1059
            range.end.row++;
1060
            line = editor.session.getLine(range.end.row);
1061
            range.end.column = /^\s*$/.test(line) ? line.length : 0;
1062
        }
1063
        var text = editor.session.getTextRange(range);
1064
        if (editor.prevOp.command == this)
1065
            exports.killRing.append(text);
1066
        else
1067
            exports.killRing.add(text);
1068

    
1069
        editor.session.remove(range);
1070
        editor.clearSelection();
1071
    },
1072
    yank: function(editor) {
1073
        editor.onPaste(exports.killRing.get() || '');
1074
        editor.keyBinding.$data.lastCommand = "yank";
1075
    },
1076
    yankRotate: function(editor) {
1077
        if (editor.keyBinding.$data.lastCommand != "yank")
1078
            return;
1079
        editor.undo();
1080
        editor.session.$emacsMarkRing.pop(); // also undo recording mark
1081
        editor.onPaste(exports.killRing.rotate());
1082
        editor.keyBinding.$data.lastCommand = "yank";
1083
    },
1084
    killRegion: {
1085
        exec: function(editor) {
1086
            exports.killRing.add(editor.getCopyText());
1087
            editor.commands.byName.cut.exec(editor);
1088
            editor.setEmacsMark(null);
1089
        },
1090
        readOnly: true,
1091
        multiSelectAction: "forEach"
1092
    },
1093
    killRingSave: {
1094
        exec: function(editor) {
1095

    
1096
            editor.$handlesEmacsOnCopy = true;
1097
            var marks = editor.session.$emacsMarkRing.slice(),
1098
                deselectedMarks = [];
1099
            exports.killRing.add(editor.getCopyText());
1100

    
1101
            setTimeout(function() {
1102
                function deselect() {
1103
                    var sel = editor.selection, range = sel.getRange(),
1104
                        pos = sel.isBackwards() ? range.end : range.start;
1105
                    deselectedMarks.push({row: pos.row, column: pos.column});
1106
                    sel.clearSelection();
1107
                }
1108
                editor.$handlesEmacsOnCopy = false;
1109
                if (editor.inMultiSelectMode) editor.forEachSelection({exec: deselect});
1110
                else deselect();
1111
                editor.setEmacsMark(null);
1112
                editor.session.$emacsMarkRing = marks.concat(deselectedMarks.reverse());
1113
            }, 0);
1114
        },
1115
        readOnly: true
1116
    },
1117
    keyboardQuit: function(editor) {
1118
        editor.selection.clearSelection();
1119
        editor.setEmacsMark(null);
1120
        editor.keyBinding.$data.count = null;
1121
    },
1122
    focusCommandLine: function(editor, arg) {
1123
        if (editor.showCommandLine)
1124
            editor.showCommandLine(arg);
1125
    }
1126
});
1127

    
1128
exports.handler.addCommands(iSearchCommandModule.iSearchStartCommands);
1129

    
1130
var commands = exports.handler.commands;
1131
commands.yank.isYank = true;
1132
commands.yankRotate.isYank = true;
1133

    
1134
exports.killRing = {
1135
    $data: [],
1136
    add: function(str) {
1137
        str && this.$data.push(str);
1138
        if (this.$data.length > 30)
1139
            this.$data.shift();
1140
    },
1141
    append: function(str) {
1142
        var idx = this.$data.length - 1;
1143
        var text = this.$data[idx] || "";
1144
        if (str) text += str;
1145
        if (text) this.$data[idx] = text;
1146
    },
1147
    get: function(n) {
1148
        n = n || 1;
1149
        return this.$data.slice(this.$data.length-n, this.$data.length).reverse().join('\n');
1150
    },
1151
    pop: function() {
1152
        if (this.$data.length > 1)
1153
            this.$data.pop();
1154
        return this.get();
1155
    },
1156
    rotate: function() {
1157
        this.$data.unshift(this.$data.pop());
1158
        return this.get();
1159
    }
1160
};
1161

    
1162
});                (function() {
1163
                    ace.require(["ace/keyboard/emacs"], function(m) {
1164
                        if (typeof module == "object" && typeof exports == "object" && module) {
1165
                            module.exports = m;
1166
                        }
1167
                    });
1168
                })();
1169
            
(23-23/244)