diff --git a/lib/ace/commands/default_commands.js b/lib/ace/commands/default_commands.js index 88621eaf..e2acb202 100644 --- a/lib/ace/commands/default_commands.js +++ b/lib/ace/commands/default_commands.js @@ -332,6 +332,11 @@ exports.commands = [{ bindKey: bindKey("Ctrl-/", "Command-/"), exec: function(editor) { editor.toggleCommentLines(); }, multiSelectAction: "forEachLine" +}, { + name: "toggleBlockComment", + bindKey: bindKey("Ctrl-Shift-/", "Command-Shift-/"), + exec: function(editor) { editor.toggleBlockComment(); }, + multiSelectAction: "forEach" }, { name: "modifyNumberUp", bindKey: bindKey("Ctrl-Shift-Up", "Alt-Shift-Up"), diff --git a/lib/ace/editor.js b/lib/ace/editor.js index 0abcecbf..9f22604c 100644 --- a/lib/ace/editor.js +++ b/lib/ace/editor.js @@ -1263,7 +1263,6 @@ var Editor = function(renderer, session) { }; /** - * * Given the currently selected range, this function either comments all the lines, or uncomments all of them. **/ this.toggleCommentLines = function() { @@ -1272,6 +1271,13 @@ var Editor = function(renderer, session) { this.session.getMode().toggleCommentLines(state, this.session, rows.first, rows.last); }; + this.toggleBlockComment = function() { + var cursor = this.getCursorPosition(); + var state = this.session.getState(cursor.row); + var range = this.getSelectionRange(); + this.session.getMode().toggleBlockComment(state, this.session, range, cursor); + }; + /** * Works like [[EditSession.getTokenAt]], except it returns a number. * @returns {Number} @@ -1440,7 +1446,6 @@ var Editor = function(renderer, session) { }); }; - /** * Executes a specific function, which can be anything that manipulates selected lines, such as copying them, duplicating them, or shifting them. * @param {Function} mover A method to call on each selected row diff --git a/lib/ace/mode/text.js b/lib/ace/mode/text.js index c0df790a..6e79baf0 100644 --- a/lib/ace/mode/text.js +++ b/lib/ace/mode/text.js @@ -36,6 +36,8 @@ var TextHighlightRules = require("./text_highlight_rules").TextHighlightRules; var Behaviour = require("./behaviour").Behaviour; var unicode = require("../unicode"); var lang = require("../lib/lang"); +var TokenIterator = require("../token_iterator").TokenIterator; +var Range = require("../range").Range; var Mode = function() { this.$tokenizer = new Tokenizer(new TextHighlightRules().getRules()); @@ -62,6 +64,8 @@ var Mode = function() { return this.$tokenizer; }; + this.lineCommentStart = ""; + this.blockComment = ""; this.toggleCommentLines = function(state, session, startRow, endRow) { var doc = session.doc; var regexpStart, lineCommentStart; @@ -84,12 +88,12 @@ var Mode = function() { if (ignoreBlankLines || /\S/.test(line)) doc.insertInLine({row: i, column: minSpace}, lineCommentStart); } - + function iter(fun) { for (var i = startRow; i <= endRow; i++) fun(doc.getLine(i), i); } - + var ignoreBlankLines = false; var shouldRemove = true; var minSpace = Infinity; @@ -112,6 +116,66 @@ var Mode = function() { iter(shouldRemove ? uncomment : comment); }; + this.toggleBlockComment = function(state, session, range, cursor) { + var comment = this.blockComment; + if (!comment) + return; + if (!comment.start && comment[0]) + comment = comment[0]; + + var iterator = new TokenIterator(session, cursor.row, cursor.column); + var token = iterator.getCurrentToken(); + + var sel = session.selection; + var initialRange = session.selection.toOrientedRange(); + var startRow, colDiff; + + if (token && /comment/.test(token.type)) { + var startRange, endRange; + while (token && /comment/.test(token.type)) { + var i = token.value.indexOf(comment.start); + if (i != -1) { + var row = iterator.getCurrentTokenRow(); + var column = iterator.getCurrentTokenColumn() + i; + startRange = new Range(row, column, row, column + comment.start.length); + break + } + token = iterator.stepBackward(); + }; + + var iterator = new TokenIterator(session, cursor.row, cursor.column); + var token = iterator.getCurrentToken(); + while (token && /comment/.test(token.type)) { + var i = token.value.indexOf(comment.end); + if (i != -1) { + var row = iterator.getCurrentTokenRow(); + var column = iterator.getCurrentTokenColumn() + i; + endRange = new Range(row, column, row, column + comment.end.length); + break; + } + token = iterator.stepForward(); + } + if (endRange) + session.remove(endRange); + if (startRange) { + session.remove(startRange); + startRow = startRange.start.row; + colDiff = -comment.start.length + } + } else { + colDiff = comment.start.length + startRow = range.start.row; + session.insert(range.end, comment.end); + session.insert(range.start, comment.start); + } + // todo: selection should have ended up in the right place automatically! + if (initialRange.start.row == startRow) + initialRange.start.column += colDiff; + if (initialRange.end.row == startRow) + initialRange.end.column += colDiff; + session.selection.fromOrientedRange(initialRange); + }; + this.getNextLineIndent = function(state, line, tab) { return this.$getIndent(line); };