diff --git a/demo/kitchen-sink/demo.js b/demo/kitchen-sink/demo.js index ab059f20..78fbd883 100644 --- a/demo/kitchen-sink/demo.js +++ b/demo/kitchen-sink/demo.js @@ -548,95 +548,6 @@ exports.launch = function(env) { } }); - canon.addCommand({ - name: "fold", - bindKey: { - win: "Alt-L", - mac: "Alt-L", - sender: "editor" - }, - exec: function(env) { - toggleFold(env, false); - } - }); - - canon.addCommand({ - name: "unfold", - bindKey: { - win: "Alt-Shift-L", - mac: "Alt-Shift-L", - sender: "editor" - }, - exec: function(env) { - toggleFold(env, true); - } - }); - - function isCommentRow(row) { - var session = env.editor.session; - var token; - var tokens = session.getTokens(row, row)[0].tokens; - var c = 0; - for (var i = 0; i < tokens.length; i++) { - token = tokens[i]; - if (/^comment/.test(token.type)) { - return c; - } else if (!/^text/.test(token.type)) { - return false; - } - c += token.value.length; - } - return false; - } - - function toggleFold(env, tryToUnfold) { - var session = env.editor.session; - var selection = env.editor.selection; - var range = selection.getRange(); - var addFold; - - if(range.isEmpty()) { - var br = session.findMatchingBracket(range.start); - var fold = session.getFoldAt(range.start.row, range.start.column); - var column; - - if (fold) { - session.expandFold(fold); - selection.setSelectionRange(fold.range); - } else if (br) { - if (range.compare(br.row, br.column) == 1) - range.end = br; - else - range.start = br; - addFold = true; - } else if ((column = isCommentRow(range.start.row)) !== false) { - var firstCommentRow = range.start.row; - var lastCommentRow = range.start.row; - var t; - while ((t = isCommentRow(firstCommentRow - 1)) !== false) { - firstCommentRow --; - column = t; - } - while (isCommentRow(lastCommentRow + 1) !== false) { - lastCommentRow ++; - } - range.start.row = firstCommentRow; - range.start.column = column + 2; - range.end.row = lastCommentRow; - range.end.column = session.getLine(lastCommentRow).length - 1; - addFold = true; - } - } else { - addFold = true; - } - if (addFold) { - var placeHolder = session.getTextRange(range); - if(placeHolder.length < 3) - return; - placeHolder = placeHolder.trim().substring(0, 3).replace(' ','','g') + "..."; - session.addFold(placeHolder, range); - } - } }; var themes = {}; diff --git a/lib/ace/commands/default_commands.js b/lib/ace/commands/default_commands.js index a09b8909..99eec74c 100644 --- a/lib/ace/commands/default_commands.js +++ b/lib/ace/commands/default_commands.js @@ -365,4 +365,33 @@ canon.addCommand({ exec: function(env, args, request) { env.editor.transposeLetters(); } }); +canon.addCommand({ + name: "fold", + bindKey: bindKey("Alt-L", "Alt-L"), + exec: function(env) { + env.editor.session.toggleFold(false); + } +}); +canon.addCommand({ + name: "unfold", + bindKey: bindKey("Alt-Shift-L", "Alt-Shift-L"), + exec: function(env) { + env.editor.session.toggleFold(true); + } +}); +canon.addCommand({ + name: "foldall", + bindKey: bindKey("Alt-Shift-0", "Alt-Shift-0"), + exec: function(env) { + env.editor.session.foldAll(); + } +}); +canon.addCommand({ + name: "unfoldall", + bindKey: bindKey("Alt-Shift-0", "Alt-Shift-0"), + exec: function(env) { + env.editor.session.unFoldAll(); + } +}); + }); diff --git a/lib/ace/edit_session.js b/lib/ace/edit_session.js index 5c9c2baa..9f22e284 100644 --- a/lib/ace/edit_session.js +++ b/lib/ace/edit_session.js @@ -91,7 +91,7 @@ var EditSession = function(text, mode) { this.doc = doc; doc.on("change", this.onChange.bind(this)); this.on("changeFold", this.onChangeFold.bind(this)); - + if (this.bgTokenizer) { this.bgTokenizer.setDocument(this.getDocument()); this.bgTokenizer.start(0); @@ -136,7 +136,7 @@ var EditSession = function(text, mode) { folds: removedFolds }); } - + this.$informUndoManager.schedule(); } @@ -148,7 +148,7 @@ var EditSession = function(text, mode) { this.doc.setValue(text); this.selection.moveCursorTo(0, 0); this.selection.clearSelection(); - + this.$resetRowCache(0); this.$deltas = []; this.$deltasDoc = []; @@ -173,6 +173,27 @@ var EditSession = function(text, mode) { return this.bgTokenizer.getTokens(firstRow, lastRow); }; + this.getTokenAt = function(row, column) { + var tokens = this.bgTokenizer.getTokens(row, row)[0].tokens; + var token, c = 0; + if (column == null) { + i = tokens.length - 1; + c = this.getLine(row).length; + } else { + for (var i = 0; i < tokens.length; i++) { + c += tokens[i].value.length; + if (c >= column) + break; + } + } + token = tokens[i]; + if (!token) + return null; + token.index = i; + token.start = c - token.value.length; + return token; + }; + this.setUndoManager = function(undoManager) { this.$undoManager = undoManager; this.$resetRowCache(0); @@ -187,7 +208,7 @@ var EditSession = function(text, mode) { var self = this; this.$syncInformUndoManager = function() { self.$informUndoManager.cancel(); - + if (self.$deltasFold.length) { self.$deltas.push({ group: "fold", @@ -195,7 +216,7 @@ var EditSession = function(text, mode) { }); self.$deltasFold = []; } - + if (self.$deltasDoc.length) { self.$deltas.push({ group: "doc", @@ -203,14 +224,14 @@ var EditSession = function(text, mode) { }); self.$deltasDoc = []; } - + if (self.$deltas.length > 0) { undoManager.execute({ action: "aceupdate", args: [self.$deltas, self] }); } - + self.$deltas = []; } this.$informUndoManager = @@ -479,7 +500,7 @@ var EditSession = function(text, mode) { this.bgTokenizer.setDocument(this.getDocument()); this.bgTokenizer.start(0); - + this.tokenRe = mode.tokenRe; this.nonTokenRe = mode.nonTokenRe; @@ -894,7 +915,7 @@ var EditSession = function(text, mode) { this.$clipRowToDocument = function(row) { return Math.max(0, Math.min(row, this.doc.getLength()-1)); }; - + this.$clipPositionToDocument = function(row, column) { column = Math.max(0, column); @@ -910,7 +931,7 @@ var EditSession = function(text, mode) { column = Math.min(this.doc.getLine(row).length, column); } } - + return { row: row, column: column @@ -1433,7 +1454,7 @@ var EditSession = function(text, mode) { column: 0 } } - + var line; var docRow = 0; var docColumn = 0; @@ -1453,11 +1474,11 @@ var EditSession = function(text, mode) { } } var doCache = !rowCache.length || i == rowCache.length; - + // clamp row before clamping column, for selection on last line var maxRow = this.getLength() - 1; - var foldLine = this.getNextFold(docRow); + var foldLine = this.getNextFoldLine(docRow); var foldStart = foldLine ? foldLine.start.row : Infinity; while (row <= screenRow) { @@ -1469,7 +1490,7 @@ var EditSession = function(text, mode) { docRow++; if (docRow > foldStart) { docRow = foldLine.end.row+1; - foldLine = this.getNextFold(docRow); + foldLine = this.getNextFoldLine(docRow, foldLine); foldStart = foldLine ? foldLine.start.row : Infinity; } } @@ -1521,7 +1542,7 @@ var EditSession = function(text, mode) { if (foldLine) { return foldLine.idxToPosition(docColumn); } - + return { row: docRow, column: docColumn @@ -1532,12 +1553,12 @@ var EditSession = function(text, mode) { // Normalize the passed in arguments. if (typeof docColumn === "undefined") var pos = this.$clipPositionToDocument(docRow.row, docRow.column); - else + else pos = this.$clipPositionToDocument(docRow, docColumn); docRow = pos.row; docColumn = pos.column; - + var LL = this.$rowCache.length; var wrapData; @@ -1579,7 +1600,7 @@ var EditSession = function(text, mode) { } var doCache = !rowCache.length || i == rowCache.length; - var foldLine = this.getNextFold(row); + var foldLine = this.getNextFoldLine(row); var foldStart = foldLine ?foldLine.start.row :Infinity; while (row < docRow) { @@ -1587,7 +1608,7 @@ var EditSession = function(text, mode) { rowEnd = foldLine.end.row + 1; if (rowEnd > docRow) break; - foldLine = this.getNextFold(rowEnd); + foldLine = this.getNextFoldLine(rowEnd, foldLine); foldStart = foldLine ?foldLine.start.row :Infinity; } else { @@ -1596,7 +1617,7 @@ var EditSession = function(text, mode) { screenRow += this.getRowLength(row); row = rowEnd; - + if (doCache) { rowCache.push({ docRow: row, @@ -1713,4 +1734,4 @@ var EditSession = function(text, mode) { require("ace/edit_session/folding").Folding.call(EditSession.prototype); exports.EditSession = EditSession; -}); +}); \ No newline at end of file diff --git a/lib/ace/edit_session/folding.js b/lib/ace/edit_session/folding.js index 127081b5..1e6e357c 100644 --- a/lib/ace/edit_session/folding.js +++ b/lib/ace/edit_session/folding.js @@ -52,7 +52,7 @@ function Folding() { var foldLine = this.getFoldLine(row); if (!foldLine) return null; - + var folds = foldLine.folds; for (var i = 0; i < folds.length; i++) { var fold = folds[i]; @@ -134,7 +134,7 @@ function Folding() { var foldLine = foldLine || this.getFoldLine(row); if (!foldLine) return null; - + var lastFold = { end: { column: 0 } }; @@ -183,7 +183,7 @@ function Folding() { } // returns the fold which starts after or contains docRow - this.getNextFold = function(docRow, startFoldLine) { + this.getNextFoldLine = function(docRow, startFoldLine) { var foldData = this.$foldData, ans; var i = 0; if (startFoldLine) @@ -251,7 +251,7 @@ function Folding() { var startColumn = fold.start.column; var endRow = fold.end.row; var endColumn = fold.end.column; - + // --- Some checking --- if (fold.placeholder.length < 2) throw "Placeholder has to be at least 2 characters"; @@ -489,8 +489,85 @@ function Folding() { return fd; }; -} + this.toggleFold = function(tryToUnfold) { + var selection = this.selection; + var range = selection.getRange(); + + if (range.isEmpty()) { + var cursor = range.start + var fold = this.getFoldAt(cursor.row, cursor.column); + var bracketPos, column; + + if (fold) { + this.expandFold(fold); + return; + } else if (bracketPos = this.findMatchingBracket(cursor)) { + if (range.comparePoint(bracketPos) == 1) { + range.end = bracketPos; + } else { + range.start = bracketPos; + range.start.column++; + range.end.column--; + } + } else if (bracketPos = this.findMatchingBracket({row: cursor.row, column: cursor.column + 1})) { + if (range.comparePoint(bracketPos) == 1) + range.end = bracketPos; + else + range.start = bracketPos; + + range.start.column++; + } else { + var token = this.getTokenAt(cursor.row, cursor.column); + if (token && /^comment|string/.test(token.type)) { + var startRow = cursor.row; + var endRow = cursor.row; + var t = token; + while ((t = this.getTokenAt(startRow - 1)) && t.type == token.type) { + startRow --; + token = t; + } + range.start.row = startRow; + range.start.column = token.start + 2; + + while ((t = this.getTokenAt(endRow + 1, 0)) && t.type == token.type) { + endRow ++; + token = t; + } + range.end.row = endRow; + range.end.column = token.start + token.value.length - 1; + } + } + } else { + var folds = this.getFoldsInRange(range); + if (tryToUnfold && folds.length) { + this.expandFolds(folds); + return; + } else if (folds.length == 1 ) { + fold = folds[0]; + } + } + + if (!fold) + fold = this.getFoldAt(range.start.row, range.start.column); + + if (fold && fold.range.toString() == range.toString()){ + this.expandFold(fold); + return + } + + + var placeholder = "..."; + if (!range.isMultiLine()) { + placeholder = this.getTextRange(range); + if(placeholder.length < 4) + return; + placeholder = placeholder.trim().substring(0, 2) + ".." + } + + this.addFold(placeholder, range); + }; +} exports.Folding = Folding; }); \ No newline at end of file diff --git a/lib/ace/layer/gutter.js b/lib/ace/layer/gutter.js index d7f43cab..280ce30e 100644 --- a/lib/ace/layer/gutter.js +++ b/lib/ace/layer/gutter.js @@ -103,13 +103,13 @@ var Gutter = function(parentEl) { var html = []; var i = config.firstRow; var lastRow = config.lastRow; - var fold = this.session.getNextFold(i); + var fold = this.session.getNextFoldLine(i); var foldStart = fold ? fold.start.row : Infinity; while (true) { if(i > foldStart) { i = fold.end.row + 1; - fold = this.session.getNextFold(i); + fold = this.session.getNextFoldLine(i, fold); foldStart = fold ?fold.start.row :Infinity; } if(i > lastRow) diff --git a/lib/ace/layer/text.js b/lib/ace/layer/text.js index 6944dca3..efb75964 100644 --- a/lib/ace/layer/text.js +++ b/lib/ace/layer/text.js @@ -260,13 +260,13 @@ var Text = function(parentEl) { this.$renderLinesFragment = function(config, firstRow, lastRow) { var fragment = this.element.ownerDocument.createDocumentFragment(), row = firstRow, - fold = this.session.getNextFold(row), + fold = this.session.getNextFoldLine(row), foldStart = fold ?fold.start.row :Infinity; while (true) { if(row > foldStart) { row = fold.end.row+1; - fold = this.session.getNextFold(row); + fold = this.session.getNextFoldLine(row, fold); foldStart = fold ?fold.start.row :Infinity; } if(row > lastRow) @@ -307,13 +307,13 @@ var Text = function(parentEl) { var firstRow = config.firstRow, lastRow = config.lastRow; var row = firstRow, - fold = this.session.getNextFold(row), + fold = this.session.getNextFoldLine(row), foldStart = fold ?fold.start.row :Infinity; while (true) { if(row > foldStart) { row = fold.end.row+1; - fold = this.session.getNextFold(row); + fold = this.session.getNextFoldLine(row, fold); foldStart = fold ?fold.start.row :Infinity; } if(row > lastRow) diff --git a/lib/ace/mode/text.js b/lib/ace/mode/text.js index 8113ac27..7f541d3e 100644 --- a/lib/ace/mode/text.js +++ b/lib/ace/mode/text.js @@ -206,13 +206,12 @@ var Mode = function() { for (var key in behaviours) { if (behaviours[key][action]) { var ret = behaviours[key][action].apply(this, arguments); - if (ret !== false) { + if (ret) { return ret; } } } } - return false; } }).call(Mode.prototype); diff --git a/lib/ace/mouse/default_handlers.js b/lib/ace/mouse/default_handlers.js index cecf15cc..5ae13ffc 100644 --- a/lib/ace/mouse/default_handlers.js +++ b/lib/ace/mouse/default_handlers.js @@ -126,18 +126,18 @@ function DefaultHandlers(editor) { mousePageY = event.getDocumentY(e); }; - var onMouseSelectionEnd = function() { + var onMouseSelectionEnd = function(e) { clearInterval(timerId); if (state == STATE_UNKNOWN) onStartSelect(pos); else if (state == STATE_DRAG) - onMouseDragSelectionEnd(); + onMouseDragSelectionEnd(e); _self.$clickSelection = null; state = STATE_UNKNOWN; }; - var onMouseDragSelectionEnd = function() { + var onMouseDragSelectionEnd = function(e) { dom.removeCssClass(editor.container, "ace_dragging"); editor.session.removeMarker(dragSelectionMarker); @@ -157,7 +157,12 @@ function DefaultHandlers(editor) { } editor.clearSelection(); - var newRange = editor.moveText(dragRange, dragCursor); + if (e && (e.ctrlKey || e.altKey)) { + var session = editor.session; + var newRange = session.insert(dragCursor, session.getTextRange(dragRange)); + } else { + var newRange = editor.moveText(dragRange, dragCursor); + } if (!newRange) { dragCursor = null; return; diff --git a/lib/ace/range.js b/lib/ace/range.js index d0caf949..596f3f57 100644 --- a/lib/ace/range.js +++ b/lib/ace/range.js @@ -102,9 +102,12 @@ var Range = function(startRow, startColumn, endRow, endColumn) { } } + this.comparePoint = function(p) { + return this.compare(p.row, p.column); + } + this.containsRange = function(range) { - var cmp = this.compareRange(range); - return (cmp == -1 || cmp == 0 || cmp == 1); + return this.comparePoint(range.start) == 0 && this.comparePoint(range.end) == 0; } this.isEnd = function(row, column) {