/
githubmirror
/
brackets
Обзор
Документация
Войти
/
githubmirror
/
brackets
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
test/spec/EditorCommandHandlers-test.js
4 325 строк
206 KB
ficristo
Editor command handlers test (#13337)
27 апр 2017, 22:57
27 апр 2017, 22:57
51e9e8c
Код
Авторство
О чём код?
/* * Copyright (c) 2012 - present Adobe Systems Incorporated. All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. * */ /*global describe, it, expect, beforeEach, afterEach, runs, waitsForDone, beforeFirst, afterLast */ define(function (require, exports, module) { 'use strict'; var EditorManager = require("editor/EditorManager"), Editor = require("editor/Editor").Editor, PreferencesManager = require("preferences/PreferencesManager"), Commands = require("command/Commands"), CommandManager = require("command/CommandManager"), LanguageManager = require("language/LanguageManager"), SpecRunnerUtils = require("spec/SpecRunnerUtils"), _ = require("thirdparty/lodash"); require("editor/EditorCommandHandlers"); var shouldIndentLineComment = Editor.getIndentLineComment(); describe("EditorCommandHandlers", function () { var defaultContent = "function foo() {\n" + " function bar() {\n" + " \n" + " a();\n" + " \n" + " }\n" + "\n" + "}"; var tabbedContent = "function funcWithTabs() {\n" + " var i = 0;\n" + " var offset = 0;\n" + "}"; var myDocument, myEditor; var testPath = SpecRunnerUtils.getTestPath("/spec/EditorCommandHandlers-test-files"), testWindow; function setupFullEditor(content, languageId) { content = content || defaultContent; languageId = languageId || "javascript"; // create dummy Document and Editor var mocks = SpecRunnerUtils.createMockEditor(content, languageId); myDocument = mocks.doc; myEditor = mocks.editor; myEditor.focus(); } function makeEditorWithRange(range, content) { content = content || defaultContent; // create editor with a visible range var mocks = SpecRunnerUtils.createMockEditor(content, "javascript", range); myDocument = mocks.doc; myEditor = mocks.editor; myEditor.focus(); } afterEach(function () { if (myDocument) { SpecRunnerUtils.destroyMockEditor(myDocument); myEditor = null; myDocument = null; } }); // Helper functions for testing cursor position / selection range function fixPos(pos) { if (!("sticky" in pos)) { pos.sticky = null; } return pos; } function fixSel(sel) { fixPos(sel.start); fixPos(sel.end); if (!("reversed" in sel)) { sel.reversed = false; } return sel; } function fixSels(sels) { sels.forEach(function (sel) { fixSel(sel); }); return sels; } function expectCursorAt(pos) { var selection = myEditor.getSelection(); expect(selection.start).toEqual(selection.end); expect(fixPos(selection.start)).toEqual(fixPos(pos)); } function expectSelection(sel) { expect(fixSel(myEditor.getSelection())).toEqual(fixSel(sel)); } function expectSelections(sels) { expect(fixSels(myEditor.getSelections())).toEqual(fixSels(sels)); } function contentWithDeletedLines(lineNums) { var lines = defaultContent.split("\n"); _.forEachRight(lineNums, function (num) { lines.splice(num, 1); }); return lines.join("\n"); } // Helper function for creating a test window function createTestWindow(spec) { SpecRunnerUtils.createTestWindowAndRun(spec, function (w) { testWindow = w; // Load module instances from brackets.test CommandManager = testWindow.brackets.test.CommandManager; Commands = testWindow.brackets.test.Commands; EditorManager = testWindow.brackets.test.EditorManager; SpecRunnerUtils.loadProjectInTestWindow(testPath); }); } // Helper function to open a new inline editor function openInlineEditor(spec) { var promise; runs(function () { promise = CommandManager.execute(Commands.CMD_ADD_TO_WORKINGSET_AND_OPEN, {fullPath: testPath + "/test.html"}); waitsForDone(promise, "Open into working set"); }); runs(function () { // Open inline editor onto test.css's ".testClass" rule promise = SpecRunnerUtils.toggleQuickEditAtOffset(EditorManager.getCurrentFullEditor(), {line: 8, ch: 11}); waitsForDone(promise, "Open inline editor"); }); runs(function () { myEditor = EditorManager.getCurrentFullEditor().getInlineWidgets()[0].editor; }); } // Helper function for closing open files in the test window function closeFilesInTestWindow() { runs(function () { var promise = CommandManager.execute(Commands.FILE_CLOSE_ALL); waitsForDone(promise, "Close all open files in working set"); // Close the save dialog without saving the changes var $dlg = testWindow.$(".modal.instance"); if ($dlg.length) { SpecRunnerUtils.clickDialogButton("dontsave"); } $dlg = null; }); } // Helper function for closing the test window function closeTestWindow() { testWindow = null; CommandManager = null; Commands = null; EditorManager = null; SpecRunnerUtils.closeTestWindow(); } /** * Invokes Toggle Line or Block Comment, expects the given selection/cursor & document text * @param {!string} expectedCommentedText * @param {!{ch:number,line:number}|{start:{ch:number,line:number},end:{ch:number,line:number}}} expectedCommentedSel * @param {?string} expectedSelText If provided, the text that should be selected after the first comment operation. * @param {!string} type Either "block" or "line". */ function testToggleComment(expectedCommentedText, expectedCommentedSel, expectedSelText, type) { var command = (type === "block" ? Commands.EDIT_BLOCK_COMMENT : Commands.EDIT_LINE_COMMENT); function expectSel(sel) { if (Array.isArray(sel)) { expectSelections(sel); } else if (sel.start) { expectSelection(sel); } else { expectCursorAt(sel); } } // Toggle comment on CommandManager.execute(command, myEditor); expect(myDocument.getText()).toEqual(expectedCommentedText); expectSel(expectedCommentedSel); if (expectedSelText) { expect(myEditor.getSelectedText()).toEqual(expectedSelText); } } function testToggleLine(expectedCommentedText, expectedCommentedSel, expectedSelText) { testToggleComment(expectedCommentedText, expectedCommentedSel, expectedSelText, "line"); } function testToggleBlock(expectedCommentedText, expectedCommentedSel, expectedSelText) { testToggleComment(expectedCommentedText, expectedCommentedSel, expectedSelText, "block"); } describe("Line comment/uncomment with indentLineComment enabled", function () { beforeEach(function () { setupFullEditor(); PreferencesManager.set("indentLineComment", true); }); afterEach(function () { PreferencesManager.set("indentLineComment", shouldIndentLineComment); }); it("should comment/uncomment a single line, cursor at start", function () { myEditor.setCursorPos(3, 0); var lines = defaultContent.split("\n"); lines[3] = " //a();"; var expectedText = lines.join("\n"); testToggleLine(expectedText, {line: 3, ch: 0}); }); it("should comment/uncomment a single line, cursor at end", function () { myEditor.setCursorPos(3, 12); var lines = defaultContent.split("\n"); lines[3] = " //a();"; var expectedText = lines.join("\n"); testToggleLine(expectedText, {line: 3, ch: 14}); }); it("should comment/uncomment first line in file", function () { myEditor.setCursorPos(0, 0); var lines = defaultContent.split("\n"); lines[0] = "//function foo() {"; var expectedText = lines.join("\n"); testToggleLine(expectedText, {line: 0, ch: 2}); }); it("should comment/uncomment a single partly-selected line", function () { // select "function" on line 1 myEditor.setSelection({line: 1, ch: 4}, {line: 1, ch: 12}); var lines = defaultContent.split("\n"); lines[1] = " //function bar() {"; var expectedText = lines.join("\n"); testToggleLine(expectedText, {start: {line: 1, ch: 6}, end: {line: 1, ch: 14}}); }); it("should comment/uncomment a single selected line", function () { // selection covers all of line's text, but not \n at end myEditor.setSelection({line: 1, ch: 0}, {line: 1, ch: 20}); var lines = defaultContent.split("\n"); lines[1] = " //function bar() {"; var expectedText = lines.join("\n"); testToggleLine(expectedText, {start: {line: 1, ch: 0}, end: {line: 1, ch: 22}}); }); it("should comment/uncomment a single fully-selected line (including LF)", function () { // selection including \n at end of line myEditor.setSelection({line: 1, ch: 0}, {line: 2, ch: 0}); var lines = defaultContent.split("\n"); lines[1] = " //function bar() {"; var expectedText = lines.join("\n"); testToggleLine(expectedText, {start: {line: 1, ch: 0}, end: {line: 2, ch: 0}}); }); it("should comment/uncomment multiple selected lines", function () { // selection including \n at end of line myEditor.setSelection({line: 1, ch: 0}, {line: 6, ch: 0}); var lines = defaultContent.split("\n"); lines[1] = " //function bar() {"; lines[2] = " // "; lines[3] = " // a();"; lines[4] = " // "; lines[5] = " //}"; var expectedText = lines.join("\n"); testToggleLine(expectedText, {start: {line: 1, ch: 0}, end: {line: 6, ch: 0}}); }); it("should comment/uncomment ragged multi-line selection", function () { myEditor.setSelection({line: 1, ch: 6}, {line: 3, ch: 9}); var lines = defaultContent.split("\n"); lines[1] = " //function bar() {"; lines[2] = " // "; lines[3] = " // a();"; var expectedText = lines.join("\n"); testToggleLine(expectedText, {start: {line: 1, ch: 8}, end: {line: 3, ch: 11}}, "nction bar() {\n // \n // a"); }); it("should comment/uncomment when selection starts & ends on whitespace lines", function () { myEditor.setSelection({line: 2, ch: 0}, {line: 4, ch: 8}); var lines = defaultContent.split("\n"); lines[2] = " //"; lines[3] = " //a();"; lines[4] = " //"; var expectedText = lines.join("\n"); testToggleLine(expectedText, {start: {line: 2, ch: 0}, end: {line: 4, ch: 10}}); }); it("should do nothing on whitespace line", function () { myEditor.setCursorPos(2, 8); testToggleLine(defaultContent, {line: 2, ch: 8}); }); it("should do nothing when only whitespace lines selected", function () { // Start with line 2 duplicated twice (3 copies total) var lines = defaultContent.split("\n"); lines.splice(2, 0, lines[2], lines[2]); var startingContent = lines.join("\n"); myDocument.setText(startingContent); myEditor.setSelection({line: 2, ch: 4}, {line: 4, ch: 4}); testToggleLine(startingContent, {start: {line: 2, ch: 4}, end: {line: 4, ch: 4}}); }); it("should comment/uncomment after select all", function () { myEditor.setSelection({line: 0, ch: 0}, {line: 7, ch: 1}); var expectedText = "//function foo() {\n" + "// function bar() {\n" + "// \n" + "// a();\n" + "// \n" + "// }\n" + "//\n" + "//}"; testToggleLine(expectedText, {start: {line: 0, ch: 0}, end: {line: 7, ch: 3}}); }); it("should comment/uncomment lines that were partially commented out already, our style", function () { // Start with line 3 commented out, with "//" at column 0 var lines = defaultContent.split("\n"); lines[3] = "// a();"; var startingContent = lines.join("\n"); myDocument.setText(startingContent); // select lines 1-3 myEditor.setSelection({line: 1, ch: 0}, {line: 4, ch: 0}); lines = defaultContent.split("\n"); lines[1] = " //function bar() {"; lines[2] = " // "; lines[3] = "//// a();"; var expectedText = lines.join("\n"); testToggleLine(expectedText, {start: {line: 1, ch: 0}, end: {line: 4, ch: 0}}); }); it("should comment/uncomment lines that were partially commented out already, comment closer to code", function () { // Start with line 3 commented out, with "//" snug against the code var lines = defaultContent.split("\n"); lines[3] = " //a();"; var startingContent = lines.join("\n"); myDocument.setText(startingContent); // select lines 1-3 myEditor.setSelection({line: 1, ch: 0}, {line: 4, ch: 0}); lines = defaultContent.split("\n"); lines[1] = " //function bar() {"; lines[2] = " // "; lines[3] = " // //a();"; var expectedText = lines.join("\n"); testToggleLine(expectedText, {start: {line: 1, ch: 0}, end: {line: 4, ch: 0}}); }); it("should uncomment indented, aligned comments", function () { // Start with lines 1-5 commented out, with "//" all aligned at column 4 var lines = defaultContent.split("\n"); lines[1] = " //function bar() {"; lines[2] = " // "; lines[3] = " // a();"; lines[4] = " // "; lines[5] = " //}"; var startingContent = lines.join("\n"); myDocument.setText(startingContent); // select lines 1-5 myEditor.setSelection({line: 1, ch: 0}, {line: 6, ch: 0}); testToggleLine(defaultContent, {start: {line: 1, ch: 0}, end: {line: 6, ch: 0}}); }); it("should uncomment ragged partial comments with empty lines in-between", function () { // Start with lines 1-5 commented out, with "//" snug up against each non-blank line's code var lines = defaultContent.split("\n"); lines[1] = " //function bar() {"; lines[2] = ""; lines[3] = " //a();"; lines[4] = ""; lines[5] = " //}"; var startingContent = lines.join("\n"); myDocument.setText(startingContent); // select lines 1-5 myEditor.setSelection({line: 1, ch: 0}, {line: 6, ch: 0}); lines = defaultContent.split("\n"); lines[2] = ""; lines[4] = ""; var expectedText = lines.join("\n"); testToggleLine(expectedText, {start: {line: 1, ch: 0}, end: {line: 6, ch: 0}}); }); it("should uncomment ragged partial comments", function () { // Start with lines 1-5 commented out, with "//" snug up against each non-blank line's code var lines = defaultContent.split("\n"); lines[1] = " //function bar() {"; lines[2] = " "; lines[3] = " //a();"; lines[4] = " "; lines[5] = " //}"; var startingContent = lines.join("\n"); myDocument.setText(startingContent); // select lines 1-5 myEditor.setSelection({line: 1, ch: 0}, {line: 6, ch: 0}); testToggleLine(defaultContent, {start: {line: 1, ch: 0}, end: {line: 6, ch: 0}}); }); describe("with multiple selections", function () { it("should toggle comments on separate lines with cursor selections", function () { myEditor.setSelections([{start: {line: 1, ch: 4}, end: {line: 1, ch: 4}}, {start: {line: 3, ch: 4}, end: {line: 3, ch: 4}}]); var lines = defaultContent.split("\n"); lines[1] = " //function bar() {"; lines[3] = " //a();"; var expectedText = lines.join("\n"); testToggleLine(expectedText, [{start: {line: 1, ch: 6}, end: {line: 1, ch: 6}, primary: false, reversed: false}, {start: {line: 3, ch : 4 }, end: {line: 3, ch: 4 }, reversed: false, primary: true}]); }); it("should toggle comments on separate lines with range selections", function () { myEditor.setSelections([{start: {line: 1, ch: 4}, end: {line: 1, ch: 6}}, {start: {line: 3, ch: 4}, end: {line: 3, ch: 6}}]); var lines = defaultContent.split("\n"); lines[1] = " //function bar() {"; lines[3] = " //a();"; var expectedText = lines.join("\n"); testToggleLine(expectedText, [{ start: {line: 1, ch: 6 }, end: {line: 1, ch: 8 }, reversed: false, primary: false }, { start: {line: 3, ch: 4 }, end : {line: 3, ch: 6 }, reversed: false, primary: true }]); }); it("should toggle comments on separate lines with multiline selections", function () { myEditor.setSelections([{start: {line: 1, ch: 4}, end: {line: 2, ch: 6}}, {start: {line: 3, ch: 4}, end: {line: 4, ch: 6}}]); var lines = defaultContent.split("\n"); lines[1] = " //function bar() {"; lines[2] = " // "; lines[3] = " //a();"; lines[4] = " //"; var expectedText = lines.join("\n"); testToggleLine(expectedText, [{start: {line: 1, ch: 6 }, end: {line: 2, ch: 8 }, reversed: false, primary: false}, {start: {line: 3, ch: 4 }, end: {line: 4, ch: 6 }, reversed: false, primary: true}]); }); it("should adjust selections appropriately at start of line", function () { myEditor.setSelections([{start: {line: 1, ch: 0}, end: {line: 1, ch: 0}}, {start: {line: 3, ch: 0}, end: {line: 3, ch: 6}}]); var lines = defaultContent.split("\n"); lines[1] = " //function bar() {"; lines[3] = " //a();"; var expectedText = lines.join("\n"); testToggleLine(expectedText, [{start: { line: 1, ch: 0 }, end: { line: 1, ch: 0 }, reversed: false, primary: false }, {start: { line: 3, ch: 0 }, end: { line: 3, ch: 8 }, reversed: false, primary: true }]); }); it("should only handle each line once, but preserve primary/reversed flags on ignored selections", function () { myEditor.setSelections([{start: {line: 1, ch: 4}, end: {line: 1, ch: 4}}, {start: {line: 1, ch: 6}, end: {line: 2, ch: 4}, primary: true}, {start: {line: 3, ch: 4}, end: {line: 3, ch: 4}}, {start: {line: 3, ch: 6}, end: {line: 3, ch: 8}, reversed: true}]); var lines = defaultContent.split("\n"); lines[1] = " //function bar() {"; lines[2] = " // "; lines[3] = " //a();"; var expectedText = lines.join("\n"); testToggleLine(expectedText, [{start: {line: 1, ch: 6}, end: {line: 1, ch: 6}, reversed: false, primary: false}, {start: {line: 1, ch: 8}, end: {line: 2, ch: 6}, reversed: false, primary: true}, {start: {line: 3, ch: 4}, end: {line: 3, ch: 4}, reversed: false, primary: false}, {start: {line: 3, ch: 6}, end: {line: 3, ch: 10}, reversed: true, primary: false}]); }); it("should properly toggle when some selections are already commented but others aren't", function () { var lines = defaultContent.split("\n"); lines[1] = " //function bar() {"; lines[3] = " a();"; lines[5] = " //}"; var startingContent = lines.join("\n"); myDocument.setText(startingContent); myEditor.setSelections([{start: {line: 1, ch: 4}, end: {line: 1, ch: 4}}, {start: {line: 3, ch: 4}, end: {line: 3, ch: 4}}, {start: {line: 5, ch: 4}, end: {line: 5, ch: 4}}]); lines[1] = " function bar() {"; lines[3] = " //a();"; lines[5] = " }"; var expectedText = lines.join("\n"); testToggleLine(expectedText, [{ start : { line : 1, ch : 4 }, end : { line : 1, ch : 4 }, reversed : false, primary : false }, { start : { line : 3, ch : 6 }, end : { line : 3, ch : 6 }, reversed : false, primary : false }, { start : { line : 5, ch : 4 }, end : { line : 5, ch : 4 }, reversed : false, primary : true }]); }); it("should properly toggle adjacent lines (not coalescing them) if there are cursors on each line", function () { var lines = defaultContent.split("\n"); lines[1] = "//" + lines[1]; lines[2] = " foo();"; // make this line non-blank so it will get commented lines[3] = "//" + lines[3]; var startingContent = lines.join("\n"); myDocument.setText(startingContent); myEditor.setSelections([{start: {line: 1, ch: 4}, end: {line: 1, ch: 4}}, {start: {line: 2, ch: 4}, end: {line: 2, ch: 4}}, {start: {line: 3, ch: 4}, end: {line: 3, ch: 4}}]); lines[1] = lines[1].slice(2); lines[2] = " //foo();"; lines[3] = lines[3].slice(2); var expectedText = lines.join("\n"); testToggleLine(expectedText, [{start: {line: 1, ch: 2}, end: {line: 1, ch: 2}, primary: false, reversed: false}, {start: {line: 2, ch: 6}, end: {line: 2, ch: 6}, primary: false, reversed: false}, {start: {line: 3, ch: 2}, end: {line: 3, ch: 2}, primary: true, reversed: false}]); }); }); }); describe("Line comment/uncomment with indentLineComment disabled", function () { beforeEach(function () { setupFullEditor(); PreferencesManager.set("indentLineComment", false); }); afterEach(function () { PreferencesManager.set("indentLineComment", shouldIndentLineComment); }); it("should comment/uncomment a single line, cursor at start", function () { myEditor.setCursorPos(3, 0); var lines = defaultContent.split("\n"); lines[3] = "// a();"; var expectedText = lines.join("\n"); testToggleLine(expectedText, {line: 3, ch: 2}); }); it("should comment/uncomment a single line, cursor at end", function () { myEditor.setCursorPos(3, 12); var lines = defaultContent.split("\n"); lines[3] = "// a();"; var expectedText = lines.join("\n"); testToggleLine(expectedText, {line: 3, ch: 14}); }); it("should comment/uncomment first line in file", function () { myEditor.setCursorPos(0, 0); var lines = defaultContent.split("\n"); lines[0] = "//function foo() {"; var expectedText = lines.join("\n"); testToggleLine(expectedText, {line: 0, ch: 2}); }); it("should comment/uncomment a single partly-selected line", function () { // select "function" on line 1 myEditor.setSelection({line: 1, ch: 4}, {line: 1, ch: 12}); var lines = defaultContent.split("\n"); lines[1] = "// function bar() {"; var expectedText = lines.join("\n"); testToggleLine(expectedText, {start: {line: 1, ch: 6}, end: {line: 1, ch: 14}}); }); it("should comment/uncomment a single selected line", function () { // selection covers all of line's text, but not \n at end myEditor.setSelection({line: 1, ch: 0}, {line: 1, ch: 20}); var lines = defaultContent.split("\n"); lines[1] = "// function bar() {"; var expectedText = lines.join("\n"); testToggleLine(expectedText, {start: {line: 1, ch: 0}, end: {line: 1, ch: 22}}); }); it("should comment/uncomment a single fully-selected line (including LF)", function () { // selection including \n at end of line myEditor.setSelection({line: 1, ch: 0}, {line: 2, ch: 0}); var lines = defaultContent.split("\n"); lines[1] = "// function bar() {"; var expectedText = lines.join("\n"); testToggleLine(expectedText, {start: {line: 1, ch: 0}, end: {line: 2, ch: 0}}); }); it("should comment/uncomment multiple selected lines", function () { // selection including \n at end of line myEditor.setSelection({line: 1, ch: 0}, {line: 6, ch: 0}); var lines = defaultContent.split("\n"); lines[1] = "// function bar() {"; lines[2] = "// "; lines[3] = "// a();"; lines[4] = "// "; lines[5] = "// }"; var expectedText = lines.join("\n"); testToggleLine(expectedText, {start: {line: 1, ch: 0}, end: {line: 6, ch: 0}}); }); it("should comment/uncomment ragged multi-line selection", function () { myEditor.setSelection({line: 1, ch: 6}, {line: 3, ch: 9}); var lines = defaultContent.split("\n"); lines[1] = "// function bar() {"; lines[2] = "// "; lines[3] = "// a();"; var expectedText = lines.join("\n"); testToggleLine(expectedText, {start: {line: 1, ch: 8}, end: {line: 3, ch: 11}}, "nction bar() {\n// \n// a"); }); it("should comment/uncomment when selection starts & ends on whitespace lines", function () { myEditor.setSelection({line: 2, ch: 0}, {line: 4, ch: 8}); var lines = defaultContent.split("\n"); lines[2] = "// "; lines[3] = "// a();"; lines[4] = "// "; var expectedText = lines.join("\n"); testToggleLine(expectedText, {start: {line: 2, ch: 0}, end: {line: 4, ch: 10}}); }); it("should comment/uncomment lines that were partially commented out already, our style", function () { // Start with line 3 commented out, with "//" at column 0 var lines = defaultContent.split("\n"); lines[3] = "// a();"; var startingContent = lines.join("\n"); myDocument.setText(startingContent); // select lines 1-3 myEditor.setSelection({line: 1, ch: 0}, {line: 4, ch: 0}); lines = defaultContent.split("\n"); lines[1] = "// function bar() {"; lines[2] = "// "; lines[3] = "//// a();"; var expectedText = lines.join("\n"); testToggleLine(expectedText, {start: {line: 1, ch: 0}, end: {line: 4, ch: 0}}); }); it("should comment/uncomment lines that were partially commented out already, comment closer to code", function () { // Start with line 3 commented out, with "//" snug against the code var lines = defaultContent.split("\n"); lines[3] = " //a();"; var startingContent = lines.join("\n"); myDocument.setText(startingContent); // select lines 1-3 myEditor.setSelection({line: 1, ch: 0}, {line: 4, ch: 0}); lines = defaultContent.split("\n"); lines[1] = "// function bar() {"; lines[2] = "// "; lines[3] = "// //a();"; var expectedText = lines.join("\n"); testToggleLine(expectedText, {start: {line: 1, ch: 0}, end: {line: 4, ch: 0}}); }); describe("with multiple selections", function () { it("should toggle comments on separate lines with cursor selections", function () { myEditor.setSelections([{start: {line: 1, ch: 4}, end: {line: 1, ch: 4}}, {start: {line: 3, ch: 4}, end: {line: 3, ch: 4}}]); var lines = defaultContent.split("\n"); lines[1] = "// function bar() {"; lines[3] = "// a();"; var expectedText = lines.join("\n"); testToggleLine(expectedText, [{start: {line: 1, ch: 6}, end: {line: 1, ch: 6}, primary: false, reversed: false}, {start: {line: 3, ch: 6}, end: {line: 3, ch: 6}, primary: true, reversed: false}]); }); it("should toggle comments on separate lines with range selections", function () { myEditor.setSelections([{start: {line: 1, ch: 4}, end: {line: 1, ch: 6}}, {start: {line: 3, ch: 4}, end: {line: 3, ch: 6}}]); var lines = defaultContent.split("\n"); lines[1] = "// function bar() {"; lines[3] = "// a();"; var expectedText = lines.join("\n"); testToggleLine(expectedText, [{start: {line: 1, ch: 6}, end: {line: 1, ch: 8}, primary: false, reversed: false}, {start: {line: 3, ch: 6}, end: {line: 3, ch: 8}, primary: true, reversed: false}]); }); it("should toggle comments on separate lines with multiline selections", function () { myEditor.setSelections([{start: {line: 1, ch: 4}, end: {line: 2, ch: 6}}, {start: {line: 3, ch: 4}, end: {line: 4, ch: 6}}]); var lines = defaultContent.split("\n"), i; for (i = 1; i <= 4; i++) { lines[i] = "//" + lines[i]; } var expectedText = lines.join("\n"); testToggleLine(expectedText, [{start: {line: 1, ch: 6}, end: {line: 2, ch: 8}, primary: false, reversed: false}, {start: {line: 3, ch: 6}, end: {line: 4, ch: 8}, primary: true, reversed: false}]); }); it("should adjust selections appropriately at start of line", function () { myEditor.setSelections([{start: {line: 1, ch: 0}, end: {line: 1, ch: 0}}, {start: {line: 3, ch: 0}, end: {line: 3, ch: 6}}]); var lines = defaultContent.split("\n"); lines[1] = "// function bar() {"; lines[3] = "// a();"; var expectedText = lines.join("\n"); testToggleLine(expectedText, [{start: {line: 1, ch: 2}, end: {line: 1, ch: 2}, primary: false, reversed: false}, {start: {line: 3, ch: 0}, end: {line: 3, ch: 8}, primary: true, reversed: false}]); }); it("should only handle each line once, but preserve primary/reversed flags on ignored selections", function () { myEditor.setSelections([{start: {line: 1, ch: 4}, end: {line: 1, ch: 4}}, {start: {line: 1, ch: 6}, end: {line: 2, ch: 4}, primary: true}, {start: {line: 3, ch: 4}, end: {line: 3, ch: 4}}, {start: {line: 3, ch: 6}, end: {line: 3, ch: 8}, reversed: true}]); var lines = defaultContent.split("\n"), i; for (i = 1; i <= 3; i++) { lines[i] = "//" + lines[i]; } var expectedText = lines.join("\n"); testToggleLine(expectedText, [{start: {line: 1, ch: 6}, end: {line: 1, ch: 6}, primary: false, reversed: false}, {start: {line: 1, ch: 8}, end: {line: 2, ch: 6}, primary: true, reversed: false}, {start: {line: 3, ch: 6}, end: {line: 3, ch: 6}, primary: false, reversed: false}, {start: {line: 3, ch: 8}, end: {line: 3, ch: 10}, primary: false, reversed: true}]); }); it("should properly toggle when some selections are already commented but others aren't", function () { var lines = defaultContent.split("\n"); lines[1] = "//" + lines[1]; lines[5] = "//" + lines[5]; var startingContent = lines.join("\n"); myDocument.setText(startingContent); myEditor.setSelections([{start: {line: 1, ch: 4}, end: {line: 1, ch: 4}}, {start: {line: 3, ch: 4}, end: {line: 3, ch: 4}}, {start: {line: 5, ch: 4}, end: {line: 5, ch: 4}}]); lines[1] = lines[1].slice(2); lines[3] = "//" + lines[3]; lines[5] = lines[5].slice(2); var expectedText = lines.join("\n"); testToggleLine(expectedText, [{start: {line: 1, ch: 2}, end: {line: 1, ch: 2}, primary: false, reversed: false}, {start: {line: 3, ch: 6}, end: {line: 3, ch: 6}, primary: false, reversed: false}, {start: {line: 5, ch: 2}, end: {line: 5, ch: 2}, primary: true, reversed: false}]); }); it("should properly toggle adjacent lines (not coalescing them) if there are cursors on each line", function () { var lines = defaultContent.split("\n"); lines[1] = "//" + lines[1]; lines[2] = " foo();"; // make this line non-blank so it will get commented lines[3] = "//" + lines[3]; var startingContent = lines.join("\n"); myDocument.setText(startingContent); myEditor.setSelections([{start: {line: 1, ch: 4}, end: {line: 1, ch: 4}}, {start: {line: 2, ch: 4}, end: {line: 2, ch: 4}}, {start: {line: 3, ch: 4}, end: {line: 3, ch: 4}}]); lines[1] = lines[1].slice(2); lines[2] = "//" + lines[2]; lines[3] = lines[3].slice(2); var expectedText = lines.join("\n"); testToggleLine(expectedText, [{start: {line: 1, ch: 2}, end: {line: 1, ch: 2}, primary: false, reversed: false}, {start: {line: 2, ch: 6}, end: {line: 2, ch: 6}, primary: false, reversed: false}, {start: {line: 3, ch: 2}, end: {line: 3, ch: 2}, primary: true, reversed: false}]); }); }); }); describe("Line comment/uncomment in languages with only block comments and with indentLineComment enabled", function () { var htmlContent = "<html>\n" + " <body>\n" + " <p>Hello</p>\n" + " </body>\n" + "</html>"; beforeEach(function () { setupFullEditor(htmlContent, "html"); PreferencesManager.set("indentLineComment", true); }); afterEach(function () { PreferencesManager.set("indentLineComment", shouldIndentLineComment); }); it("should comment/uncomment a single line, cursor at start", function () { myEditor.setCursorPos(2, 0); var lines = htmlContent.split("\n"); lines[2] = " <!--<p>Hello</p>-->"; var expectedText = lines.join("\n"); testToggleLine(expectedText, {line: 2, ch: 0}); // Uncomment testToggleLine(htmlContent, {line: 2, ch: 0}); }); it("should comment/uncomment a block", function () { myEditor.setSelection({line: 1, ch: 7}, {line: 3, ch: 7}); var expectedText = "<html>\n" + " <!--\n" + " <body>\n" + " <p>Hello</p>\n" + " </body>\n" + " -->\n" + "</html>"; testToggleLine(expectedText, {start: {line: 2, ch: 7}, end: {line: 4, ch: 7}}); // Uncomment testToggleLine(htmlContent, {start: {line: 1, ch: 7}, end: {line: 3, ch: 7}}); }); it("should comment/uncomment a block with not closing tag ", function () { myEditor.setSelection({line: 1, ch: 7}, {line: 2, ch: 7}); var expectedText = "<html>\n" + " <!--\n" + " <body>\n" + " <p>Hello</p>\n" + " -->\n" + " </body>\n" + "</html>"; testToggleLine(expectedText, {start: {line: 2, ch: 7}, end: {line: 3, ch: 7}}); // Uncomment testToggleLine(htmlContent, {start: {line: 1, ch: 7}, end: {line: 2, ch: 7}}); }); it("should comment/uncomment a block with not closing tag at end of file", function () { myEditor.setSelection({line: 3, ch: 9}, {line: 4, ch: 5}); var expectedText = "<html>\n" + " <body>\n" + " <p>Hello</p>\n" + " <!--\n" + " </body>\n" + "</html>-->\n"; testToggleLine(expectedText, {start: {line: 4, ch: 9}, end: {line: 5, ch: 5}}); // Uncomment testToggleLine(htmlContent + "\n", {start: {line: 3, ch: 9}, end: {line: 4, ch: 5}}); }); }); describe("Line comment/uncomment in languages with only block comments and with indentLineComment enabled and use of Tabs", function () { var htmlContent = "<html>\n" + "\t<body>\n" + "\t\t<p>Hello</p>\n" + "\t</body>\n" + "</html>"; var shouldUseTabChar = Editor.getUseTabChar(); beforeEach(function () { setupFullEditor(htmlContent, "html"); PreferencesManager.set("indentLineComment", true); PreferencesManager.set("useTabChar", true); }); afterEach(function () { PreferencesManager.set("indentLineComment", shouldIndentLineComment); PreferencesManager.set("useTabChar", shouldUseTabChar); }); it("should comment/uncomment a single line, cursor at start", function () { myEditor.setCursorPos(2, 0); var lines = htmlContent.split("\n"); lines[2] = "\t\t<!--<p>Hello</p>-->"; var expectedText = lines.join("\n"); testToggleLine(expectedText, {line: 2, ch: 0}); }); it("should comment/uncomment a block", function () { myEditor.setSelection({line: 1, ch: 4}, {line: 3, ch: 4}); var expectedText = "<html>\n" + "\t<!--\n" + "\t<body>\n" + "\t\t<p>Hello</p>\n" + "\t</body>\n" + "\t-->\n" + "</html>"; testToggleLine(expectedText, {start: {line: 2, ch: 4}, end: {line: 4, ch: 4}}); // Uncomment testToggleLine(htmlContent, {start: {line: 1, ch: 4}, end: {line: 3, ch: 4}}); }); it("should comment/uncomment a block with not closing tag ", function () { myEditor.setSelection({line: 1, ch: 4}, {line: 2, ch: 7}); var expectedText = "<html>\n" + "\t<!--\n" + "\t<body>\n" + "\t\t<p>Hello</p>\n" + "\t\t-->\n" + "\t</body>\n" + "</html>"; testToggleLine(expectedText, {start: {line: 2, ch: 4}, end: {line: 3, ch: 7}}); // Uncomment testToggleLine(htmlContent, {start: {line: 1, ch: 4}, end: {line: 2, ch: 7}}); }); it("should comment/uncomment a block with not closing tag at end of file", function () { myEditor.setSelection({line: 3, ch: 6}, {line: 4, ch: 2}); var expectedText = "<html>\n" + "\t<body>\n" + "\t\t<p>Hello</p>\n" + "\t<!--\n" + "\t</body>\n" + "</html>-->\n"; testToggleLine(expectedText, {start: {line: 4, ch: 6}, end: {line: 5, ch: 2}}); // Uncomment testToggleLine(htmlContent + "\n", {start: {line: 3, ch: 6}, end: {line: 4, ch: 2}}); }); }); // The "block comment" command should be unaffected by indentLineComment preference. describe("Block comment/uncomment in languages with only block comments and with indentLineComment enabled", function () { var htmlContent = "<html>\n" + " <body>\n" + " <p>Hello</p>\n" + " </body>\n" + "</html>"; beforeEach(function () { setupFullEditor(htmlContent, "html"); PreferencesManager.set("indentLineComment", true); }); afterEach(function () { PreferencesManager.set("indentLineComment", shouldIndentLineComment); }); it("should comment/uncomment a single line, cursor at start", function () { myEditor.setCursorPos(2, 0); var lines = htmlContent.split("\n"); lines[2] = "<!----> <p>Hello</p>"; var expectedText = lines.join("\n"); testToggleBlock(expectedText, {line: 2, ch: 4}); }); it("should comment/uncomment a single line, cursor at end", function () { myEditor.setCursorPos(2, 20); var lines = htmlContent.split("\n"); lines[2] = " <p>Hello</p><!---->"; var expectedText = lines.join("\n"); testToggleBlock(expectedText, {line: 2, ch: 24}); }); it("should comment/uncomment a block", function () { myEditor.setSelection({line: 1, ch: 4}, {line: 3, ch: 11}); var expectedText = "<html>\n" + " <!--<body>\n" + " <p>Hello</p>\n" + " </body>-->\n" + "</html>"; testToggleBlock(expectedText, {start: {line: 1, ch: 8}, end: {line: 3, ch: 11}}); }); }); describe("Line comment in languages with mutiple line comment prefixes", function () { // Define a special version of JavaScript for testing purposes LanguageManager.defineLanguage("javascript2", { "name": "JavaScript2", "mode": "javascript", "fileExtensions": ["js2"], "lineComment": ["//", "////", "#"] }); beforeEach(function () { setupFullEditor(null, "javascript2"); }); it("should comment using the first prefix", function () { // select first 2 lines myEditor.setSelection({line: 0, ch: 4}, {line: 1, ch: 12}); var lines = defaultContent.split("\n"); lines[0] = "//function foo() {"; lines[1] = "// function bar() {"; var expectedText = lines.join("\n"); testToggleLine(expectedText, {start: {line: 0, ch: 6}, end: {line: 1, ch: 14}}); }); it("should uncomment every prefix", function () { // Start with lines 1-5 commented out, with multiple line comment variations var lines = defaultContent.split("\n"); lines[1] = "// function bar() {"; lines[2] = " // "; lines[3] = " //// a();"; lines[4] = " "; lines[5] = "# }"; var startingContent = lines.join("\n"); myDocument.setText(startingContent); // select lines 1-5 myEditor.setSelection({line: 1, ch: 0}, {line: 6, ch: 0}); testToggleLine(defaultContent, {start: {line: 1, ch: 0}, end: {line: 6, ch: 0}}); }); it("should only uncomment the first prefix", function () { // Start with lines 1-3 commented out, with multiple line comment variations var lines = defaultContent.split("\n"); lines[1] = "//# function bar() {"; lines[2] = "// "; lines[3] = "////// a();"; var startingContent = lines.join("\n"); myDocument.setText(startingContent); lines = defaultContent.split("\n"); lines[1] = "# function bar() {"; lines[2] = " "; lines[3] = "// a();"; var expectedContent = lines.join("\n"); // select lines 1-3 myEditor.setSelection({line: 1, ch: 0}, {line: 4, ch: 0}); testToggleLine(expectedContent, {start: {line: 1, ch: 0}, end: {line: 4, ch: 0}}); }); }); describe("Line comment in languages with no given line comment prefix", function () { beforeEach(function () { setupFullEditor(null, "unknown"); }); it("should properly restore the cursor", function () { myEditor.setSelection({line: 1, ch: 4}, {line: 1, ch: 4}); testToggleLine(defaultContent, {start: {line: 1, ch: 4}, end: {line: 1, ch: 4}}); }); it("should properly restore the range selection", function () { myEditor.setSelection({line: 1, ch: 4}, {line: 1, ch: 6}); testToggleLine(defaultContent, {start: {line: 1, ch: 4}, end: {line: 1, ch: 6}}); }); it("should properly restore the cursors", function () { myEditor.setSelections([{start: {line: 1, ch: 4}, end: {line: 1, ch: 4}}, {start: {line: 3, ch: 4}, end: {line: 3, ch: 4}}]); testToggleLine(defaultContent, [ {start: {line: 1, ch: 4}, end: {line: 1, ch: 4}, reversed: false, primary: false}, {start: {line: 3, ch: 4}, end: {line: 3, ch: 4}, reversed: false, primary: true} ]); }); it("should properly restore the range selections", function () { myEditor.setSelections([{start: {line: 1, ch: 4}, end: {line: 1, ch: 6}}, {start: {line: 3, ch: 4}, end: {line: 3, ch: 6}}]); testToggleLine(defaultContent, [ {start: {line: 1, ch: 4}, end: {line: 1, ch: 6}, reversed: false, primary: false}, {start: {line: 3, ch: 4}, end: {line: 3, ch: 6}, reversed: false, primary: true} ]); }); it("should properly restore primary/reversed range selections", function () { myEditor.setSelections([{start: {line: 1, ch: 4}, end: {line: 1, ch: 4}, primary: true}, {start: {line: 3, ch: 4}, end: {line: 3, ch: 12}, reversed: true}]); testToggleLine(defaultContent, [ {start: {line: 1, ch: 4}, end: {line: 1, ch: 4}, reversed: false, primary: true}, {start: {line: 3, ch: 4}, end: {line: 3, ch: 12}, reversed: true, primary: false} ]); }); }); describe("Block comment/uncomment", function () { beforeEach(setupFullEditor); it("should block comment/uncomment, cursor at start of line", function () { myEditor.setCursorPos(0, 0); var lines = defaultContent.split("\n"); lines[0] = "/**/function foo() {"; var expectedText = lines.join("\n"); testToggleBlock(expectedText, {line: 0, ch: 2}); }); it("should block comment/uncomment, cursor to left of existing block comment", function () { // Start with part of line 3 wrapped in a block comment var lines = defaultContent.split("\n"); lines[3] = " /*a();*/"; var startingContent = lines.join("\n"); myDocument.setText(startingContent); // put cursor to left of block myEditor.setCursorPos(3, 4); lines[3] = " /**/ /*a();*/"; var expectedText = lines.join("\n"); testToggleBlock(expectedText, {line: 3, ch: 6}); }); it("should block comment/uncomment, subset of line selected", function () { myEditor.setSelection({line: 1, ch: 13}, {line: 1, ch: 18}); // select "bar()" var lines = defaultContent.split("\n"); lines[1] = " function /*bar()*/ {"; var expectedText = lines.join("\n"); // Selects just text within block testToggleBlock(expectedText, {start: {line: 1, ch: 15}, end: {line: 1, ch: 20}}); }); it("should block uncomment, cursor within existing sub-line block comment", function () { // Start with part of line 1 wrapped in a block comment var lines = defaultContent.split("\n"); lines[1] = " function /*bar()*/ {"; var startingContent = lines.join("\n"); myDocument.setText(startingContent); // put cursor within block myEditor.setCursorPos(1, 18); testToggleBlock(defaultContent, {line: 1, ch: 16}); }); it("should block uncomment, cursor within existing block comment suffix", function () { // Start with part of line 1 wrapped in a block comment var lines = defaultContent.split("\n"); lines[1] = " function /*bar()*/ {"; var startingContent = lines.join("\n"); myDocument.setText(startingContent); // put cursor within block myEditor.setCursorPos(1, 21); testToggleBlock(defaultContent, {line: 1, ch: 18}); }); it("should block uncomment, selection covering whole sub-line block comment", function () { // Start with part of line 1 wrapped in a block comment var lines = defaultContent.split("\n"); lines[1] = " function /*bar()*/ {"; var startingContent = lines.join("\n"); myDocument.setText(startingContent); // select whole comment myEditor.setSelection({line: 1, ch: 13}, {line: 1, ch: 22}); testToggleBlock(defaultContent, {start: {line: 1, ch: 13}, end: {line: 1, ch: 18}}); // just text that was uncommented }); it("should block comment/uncomment, selection from mid-line end of line", function () { myEditor.setSelection({line: 3, ch: 8}, {line: 3, ch: 12}); var lines = defaultContent.split("\n"); lines[3] = " /*a();*/"; var expectedText = lines.join("\n"); // Selects just text within block testToggleBlock(expectedText, {start: {line: 3, ch: 10}, end: {line: 3, ch: 14}}); }); it("should block comment/uncomment, all of line selected but not newline", function () { myEditor.setSelection({line: 3, ch: 0}, {line: 3, ch: 12}); var lines = defaultContent.split("\n"); lines[3] = "/* a();*/"; var expectedText = lines.join("\n"); // Selects just text within block testToggleBlock(expectedText, {start: {line: 3, ch: 2}, end: {line: 3, ch: 14}}); }); it("should block comment/uncomment, all of line selected including newline", function () { myEditor.setSelection({line: 3, ch: 0}, {line: 4, ch: 0}); var lines = defaultContent.split("\n"); lines.splice(3, 1, "/*", lines[3], "*/"); // inserts new delimiter lines var expectedText = lines.join("\n"); // Selects original line, but not block-delimiter lines testToggleBlock(expectedText, {start: {line: 4, ch: 0}, end: {line: 5, ch: 0}}); }); it("should block comment/uncomment, multiple lines selected", function () { myEditor.setSelection({line: 1, ch: 0}, {line: 6, ch: 0}); var lines = defaultContent.split("\n"); lines.splice(6, 0, "*/"); // inserts new delimiter lines lines.splice(1, 0, "/*"); var expectedText = lines.join("\n"); // Selects original lines, but not block-delimiter lines testToggleBlock(expectedText, {start: {line: 2, ch: 0}, end: {line: 7, ch: 0}}); }); it("should block comment/uncomment, multiple partial lines selected", function () { myEditor.setSelection({line: 1, ch: 13}, {line: 3, ch: 9}); var lines = defaultContent.split("\n"); lines[1] = " function /*bar() {"; lines[3] = " a*/();"; var expectedText = lines.join("\n"); // Selects just text within block testToggleBlock(expectedText, {start: {line: 1, ch: 15}, end: {line: 3, ch: 9}}); }); // Whitespace within block comments var BLOCK_CONTAINING_WS = "function foo()\n" + "/*\n" + " a();\n" + " \n" + " b();\n" + "*/\n" + "}"; it("should block uncomment, cursor in whitespace within block comment", function () { myDocument.setText(BLOCK_CONTAINING_WS); myEditor.setCursorPos(3, 2); // middle of blank line var lines = BLOCK_CONTAINING_WS.split("\n"); lines.splice(5, 1); // removes delimiter lines lines.splice(1, 1); var expectedText = lines.join("\n"); testToggleBlock(expectedText, {line: 2, ch: 2}); }); it("should block uncomment, selection in whitespace within block comment", function () { myDocument.setText(BLOCK_CONTAINING_WS); myEditor.setSelection({line: 3, ch: 0}, {line: 3, ch: 4}); var lines = BLOCK_CONTAINING_WS.split("\n"); lines.splice(5, 1); // removes delimiter lines lines.splice(1, 1); var expectedText = lines.join("\n"); testToggleBlock(expectedText, {start: {line: 2, ch: 0}, end: {line: 2, ch: 4}}); }); // Selections mixing whitespace and existing block comments var WS_SURROUNDING_BLOCK = "function foo()\n" + " \n" + " /*a();\n" + " \n" + " b();*/\n" + " \n" + "}"; it("should block uncomment, selection covers block comment plus whitespace before", function () { myDocument.setText(WS_SURROUNDING_BLOCK); myEditor.setSelection({line: 1, ch: 0}, {line: 4, ch: 10}); // start of blank line to end of block comment var lines = WS_SURROUNDING_BLOCK.split("\n"); lines[2] = " a();"; lines[4] = " b();"; var expectedText = lines.join("\n"); testToggleBlock(expectedText, {start: {line: 1, ch: 0}, end: {line: 4, ch: 8}}); }); it("should block uncomment, selection covers block comment plus whitespace after", function () { myDocument.setText(WS_SURROUNDING_BLOCK); myEditor.setSelection({line: 2, ch: 4}, {line: 5, ch: 4}); // start of block comment to end of blank line var lines = WS_SURROUNDING_BLOCK.split("\n"); lines[2] = " a();"; lines[4] = " b();"; var expectedText = lines.join("\n"); testToggleBlock(expectedText, {start: {line: 2, ch: 4}, end: {line: 5, ch: 4}}); }); it("should block uncomment, selection covers part of block comment plus whitespace before", function () { myDocument.setText(WS_SURROUNDING_BLOCK); myEditor.setSelection({line: 1, ch: 0}, {line: 3, ch: 4}); // start of blank line to middle of block comment var lines = WS_SURROUNDING_BLOCK.split("\n"); lines[2] = " a();"; lines[4] = " b();"; var expectedText = lines.join("\n"); testToggleBlock(expectedText, {start: {line: 1, ch: 0}, end: {line: 3, ch: 4}}); }); it("should block uncomment, selection covers part of block comment plus whitespace after", function () { myDocument.setText(WS_SURROUNDING_BLOCK); myEditor.setSelection({line: 3, ch: 4}, {line: 5, ch: 4}); // middle of block comment to end of blank line var lines = WS_SURROUNDING_BLOCK.split("\n"); lines[2] = " a();"; lines[4] = " b();"; var expectedText = lines.join("\n"); testToggleBlock(expectedText, {start: {line: 3, ch: 4}, end: {line: 5, ch: 4}}); }); it("should block uncomment, selection covers block comment plus whitespace on both sides", function () { myDocument.setText(WS_SURROUNDING_BLOCK); myEditor.setSelection({line: 1, ch: 0}, {line: 5, ch: 4}); // start of first blank line to end of last blank line var lines = WS_SURROUNDING_BLOCK.split("\n"); lines[2] = " a();"; lines[4] = " b();"; var expectedText = lines.join("\n"); testToggleBlock(expectedText, {start: {line: 1, ch: 0}, end: {line: 5, ch: 4}}); }); // Selections mixing uncommented text and existing block comments it("should block uncomment, selection covers block comment plus other text", function () { // Start with part of line 1 wrapped in a block comment var lines = defaultContent.split("\n"); lines[1] = " function /*bar()*/ {"; var startingContent = lines.join("\n"); myDocument.setText(startingContent); // select more of line 1 myEditor.setSelection({line: 1, ch: 4}, {line: 1, ch: 24}); testToggleBlock(defaultContent, {start: {line: 1, ch: 4}, end: {line: 1, ch: 20}}); // range endpoints still align with same text }); it("should block uncomment, selection covers multi-line block comment plus other text", function () { var content = "function foo()\n" + " \n" + " /*a();\n" + " \n" + " b();*/\n" + " c();\n" + "}"; myDocument.setText(content); myEditor.setSelection({line: 0, ch: 5}, {line: 5, ch: 5}); // middle of first line of code to middle of line following comment var lines = content.split("\n"); lines[2] = " a();"; lines[4] = " b();"; var expectedText = lines.join("\n"); testToggleBlock(expectedText, {start: {line: 0, ch: 5}, end: {line: 5, ch: 5}}); }); // Selections including multiple separate block comments // We no-op in these cases since it's ambiguous - can't nest block comments, but was multiple independent uncomments intended? it("should do nothing, selection covers parts of multiple block comments", function () { // Start with part of line 1 wrapped in a block comment var lines = defaultContent.split("\n"); lines[1] = " /*function*/ /*bar()*/ {"; var startingContent = lines.join("\n"); myDocument.setText(startingContent); // select end of 1st comment, start of 2nd comment, and the space between them myEditor.setSelection({line: 1, ch: 9}, {line: 1, ch: 22}); testToggleBlock(startingContent, {start: {line: 1, ch: 9}, end: {line: 1, ch: 22}}); // no change }); it("should do nothing, selection covers all of multiple block comments", function () { // Start with part of line 1 wrapped in a block comment var lines = defaultContent.split("\n"); lines[1] = " /*function*/ /*bar()*/ {"; var startingContent = lines.join("\n"); myDocument.setText(startingContent); // select both block comments and the space between them, but nothing else myEditor.setSelection({line: 1, ch: 4}, {line: 1, ch: 26}); testToggleBlock(startingContent, {start: {line: 1, ch: 4}, end: {line: 1, ch: 26}}); // no change }); it("should do nothing, selection covers multiple block comments & nothing else", function () { // Start with part of line 1 wrapped in a block comment var lines = defaultContent.split("\n"); lines[1] = " /*function*//*bar()*/ {"; var startingContent = lines.join("\n"); myDocument.setText(startingContent); // select both block comments, but nothing else myEditor.setSelection({line: 1, ch: 4}, {line: 1, ch: 25}); testToggleBlock(startingContent, {start: {line: 1, ch: 4}, end: {line: 1, ch: 25}}); // no change }); it("should do nothing, selection covers multiple block comments plus other text", function () { // Start with part of line 1 wrapped in a block comment var lines = defaultContent.split("\n"); lines[1] = " /*function*/ /*bar()*/ {"; var startingContent = lines.join("\n"); myDocument.setText(startingContent); // select all of line 1 (but not newline) myEditor.setSelection({line: 1, ch: 0}, {line: 1, ch: 28}); testToggleBlock(startingContent, {start: {line: 1, ch: 0}, end: {line: 1, ch: 28}}); // no change }); describe("with multiple selections", function () { it("should comment out multiple selections/cursors, preserving primary/reversed selections", function () { var lines = defaultContent.split("\n"); lines[1] = lines[1].substr(0, 4) + "/**/" + lines[1].substr(4); lines[3] = lines[3].substr(0, 4) + "/*" + lines[3].substr(4, 8) + "*/" + lines[3].substr(12); myEditor.setSelections([{start: {line: 1, ch: 4}, end: {line: 1, ch: 4}, primary: true}, {start: {line: 3, ch: 4}, end: {line: 3, ch: 12}, reversed: true}]); testToggleBlock(lines.join("\n"), [{start: {line: 1, ch: 6}, end: {line: 1, ch: 6}, primary: true, reversed: false}, {start: {line: 3, ch: 6}, end: {line: 3, ch: 14}, primary: false, reversed: true}]); }); it("should skip the case where a selection covers multiple block comments, but still track it and handle other selections", function () { var lines = defaultContent.split("\n"); lines[4] = " /*a*/ /*()*/ {"; var startingContent = lines.join("\n"); myDocument.setText(startingContent); myEditor.setSelections([{start: {line: 0, ch: 0}, end: {line: 1, ch: 0}}, {start: {line: 4, ch: 0}, end: {line: 4, ch: 18}, reversed: true}]); lines.splice(1, 0, "*/"); lines.splice(0, 0, "/*"); testToggleBlock(lines.join("\n"), [ {start: {line: 1, ch: 0}, end: {line: 2, ch: 0}, primary: false, reversed: false}, {start: {line: 6, ch: 0}, end: {line: 6, ch: 18}, primary: true, reversed: true} ]); }); }); }); // If the cursor's/selection's lines contain nothing but line comments and whitespace, we assume the user // meant line-uncomment (i.e. delegate to Toggle Line Comment). In all other cases, we ignore the line comment // and create a new block comment. describe("Block comment around line comments", function () { beforeEach(setupFullEditor); // Selections including existing line comments (and possibly whitespace) it("should switch to line uncomment mode, cursor inside line comment (with only whitespace to left)", function () { // Start with part of line 1 line-commented var lines = defaultContent.split("\n"); lines[1] = " //function bar() {"; var startingContent = lines.join("\n"); myDocument.setText(startingContent); myEditor.setCursorPos(1, 18); testToggleBlock(defaultContent, {line: 1, ch: 16}); }); it("should switch to line uncomment, cursor in whitespace to left of line comment", function () { // #2342 // Start with part of line 1 line-commented var lines = defaultContent.split("\n"); lines[1] = " //function bar() {"; var startingContent = lines.join("\n"); myDocument.setText(startingContent); myEditor.setCursorPos(1, 0); testToggleBlock(defaultContent, {line: 1, ch: 0}); }); it("should switch to line uncomment, some of line-comment selected (only whitespace to left)", function () { var content = "function foo()\n" + " // Comment\n" + "}"; myDocument.setText(content); myEditor.setSelection({line: 1, ch: 6}, {line: 1, ch: 13}); // just " Commen" var lines = content.split("\n"); lines[1] = " Comment"; var expectedText = lines.join("\n"); testToggleBlock(expectedText, {start: {line: 1, ch: 4}, end: {line: 1, ch: 11}}); }); it("should switch to line uncomment, some of line-comment selected including last char (only whitespace to left)", function () { // #2337 var content = "function foo()\n" + " // Comment\n" + "}"; myDocument.setText(content); myEditor.setSelection({line: 1, ch: 6}, {line: 1, ch: 14}); // everything but leading "//" var lines = content.split("\n"); lines[1] = " Comment"; var expectedText = lines.join("\n"); testToggleBlock(expectedText, {start: {line: 1, ch: 4}, end: {line: 1, ch: 12}}); }); it("should switch to line uncomment, all of line-comment selected (only whitespace to left)", function () { // #2342 var content = "function foo()\n" + " // Comment\n" + "}"; myDocument.setText(content); myEditor.setSelection({line: 1, ch: 4}, {line: 1, ch: 14}); // include "//" var lines = content.split("\n"); lines[1] = " Comment"; var expectedText = lines.join("\n"); testToggleBlock(expectedText, {start: {line: 1, ch: 4}, end: {line: 1, ch: 12}}); }); // Selections that don't mix code & line-comment, but are on a line that does contain both it("should insert block comment, cursor inside line comment (with code to left)", function () { // Start with comment ending line 1 var lines = defaultContent.split("\n"); lines[1] = " function bar() { // comment"; var startingContent = lines.join("\n"); myDocument.setText(startingContent); myEditor.setCursorPos(1, 24); // between space and "c" lines = defaultContent.split("\n"); lines[1] = " function bar() { // /**/comment"; var expectedText = lines.join("\n"); testToggleBlock(expectedText, {line: 1, ch: 26}); }); it("should insert block comment, cursor in code to left of line comment", function () { // Start with comment ending line 1 var lines = defaultContent.split("\n"); lines[1] = " function bar() { // comment"; var startingContent = lines.join("\n"); myDocument.setText(startingContent); myEditor.setCursorPos(1, 12); lines[1] = " function/**/ bar() { // comment"; var expectedText = lines.join("\n"); testToggleBlock(expectedText, {line: 1, ch: 14}); }); it("should block comment, some of line-comment selected (with code to left)", function () { var content = "function foo()\n" + " f(); // Comment\n" + "}"; myDocument.setText(content); myEditor.setSelection({line: 1, ch: 11}, {line: 1, ch: 18}); // just " Commen" var lines = content.split("\n"); lines[1] = " f(); ///* Commen*/t"; var expectedText = lines.join("\n"); testToggleBlock(expectedText, {start: {line: 1, ch: 13}, end: {line: 1, ch: 20}}); }); it("should block comment, some of line-comment selected including last char (with code to left)", function () { // #2337 var content = "function foo()\n" + " f(); // Comment\n" + "}"; myDocument.setText(content); myEditor.setSelection({line: 1, ch: 11}, {line: 1, ch: 19}); // everything but leading "//" var lines = content.split("\n"); lines[1] = " f(); ///* Comment*/"; var expectedText = lines.join("\n"); testToggleBlock(expectedText, {start: {line: 1, ch: 13}, end: {line: 1, ch: 21}}); }); it("should block comment, all of line-comment selected (with code to left)", function () { // #2342 var content = "function foo()\n" + " f(); // Comment\n" + "}"; myDocument.setText(content); myEditor.setSelection({line: 1, ch: 9}, {line: 1, ch: 19}); // include "//" var lines = content.split("\n"); lines[1] = " f(); /*// Comment*/"; var expectedText = lines.join("\n"); testToggleBlock(expectedText, {start: {line: 1, ch: 11}, end: {line: 1, ch: 21}}); }); // Full-line/multiline selections containing only line comments and whitespace it("should switch to line uncomment, all of line-comment line selected (following line is code)", function () { var content = "function foo()\n" + " // Comment\n" + "}"; myDocument.setText(content); myEditor.setSelection({line: 1, ch: 0}, {line: 2, ch: 0}); var lines = content.split("\n"); lines[1] = " Comment"; var expectedText = lines.join("\n"); testToggleBlock(expectedText, {start: {line: 1, ch: 0}, end: {line: 2, ch: 0}}); }); it("should switch to line uncomment, all of line-comment line selected (following line is whitespace)", function () { var content = "function foo()\n" + " // Comment\n" + " \n" + "}"; myDocument.setText(content); myEditor.setSelection({line: 1, ch: 0}, {line: 2, ch: 0}); var lines = content.split("\n"); lines[1] = " Comment"; var expectedText = lines.join("\n"); testToggleBlock(expectedText, {start: {line: 1, ch: 0}, end: {line: 2, ch: 0}}); }); it("should switch to line uncomment, all of line-comment line selected (following line is line comment)", function () { var content = "function foo()\n" + " // Comment\n" + " // Comment 2\n" + "}"; myDocument.setText(content); myEditor.setSelection({line: 1, ch: 0}, {line: 2, ch: 0}); var lines = content.split("\n"); lines[1] = " Comment"; var expectedText = lines.join("\n"); testToggleBlock(expectedText, {start: {line: 1, ch: 0}, end: {line: 2, ch: 0}}); }); it("should switch to line uncomment, all of line-comment line selected (following line is block comment)", function () { var content = "function foo()\n" + " // Comment\n" + " /* Comment 2 */\n" + "}"; myDocument.setText(content); myEditor.setSelection({line: 1, ch: 0}, {line: 2, ch: 0}); var lines = content.split("\n"); lines[1] = " Comment"; var expectedText = lines.join("\n"); testToggleBlock(expectedText, {start: {line: 1, ch: 0}, end: {line: 2, ch: 0}}); }); it("should line uncomment, multiple line comments selected", function () { // Start with all of lines 1-5 line-commented var lines = defaultContent.split("\n"); lines[1] = "// function bar() {"; lines[2] = "// "; lines[3] = "// a();"; lines[4] = "// "; lines[5] = "// }"; var content = lines.join("\n"); myDocument.setText(content); myEditor.setSelection({line: 1, ch: 0}, {line: 6, ch: 0}); testToggleBlock(defaultContent, {start: {line: 1, ch: 0}, end: {line: 6, ch: 0}}); }); // Selections mixing uncommented code & line comments var lineCommentCode = "function foo() {\n" + " \n" + " // Floating comment\n" + " \n" + " // Attached comment\n" + " function bar() {\n" + " a();\n" + " b(); // post comment\n" + " }\n" + " \n" + " bar();\n" + " // Attached above\n" + " \n" + " // Final floating comment\n" + " \n" + "}"; it("should line uncomment, multiline selection covers line comment plus whitespace", function () { myDocument.setText(lineCommentCode); myEditor.setSelection({line: 1, ch: 0}, {line: 3, ch: 4}); var lines = lineCommentCode.split("\n"); lines[2] = " Floating comment"; var expectedText = lines.join("\n"); testToggleBlock(expectedText, {start: {line: 1, ch: 0}, end: {line: 3, ch: 4}}); }); it("should switch to line uncomment mode, selection starts in whitespace & ends in middle of line comment", function () { // #2342 myDocument.setText(lineCommentCode); myEditor.setSelection({line: 2, ch: 2}, {line: 2, ch: 10}); // stops with "Flo" var lines = lineCommentCode.split("\n"); lines[2] = " Floating comment"; var expectedText = lines.join("\n"); testToggleBlock(expectedText, {start: {line: 2, ch: 2}, end: {line: 2, ch: 8}}); }); it("should switch to line uncomment mode, selection starts in whitespace & ends at end of line comment", function () { // #2337, #2342 myDocument.setText(lineCommentCode); myEditor.setSelection({line: 2, ch: 2}, {line: 2, ch: 23}); var lines = lineCommentCode.split("\n"); lines[2] = " Floating comment"; var expectedText = lines.join("\n"); testToggleBlock(expectedText, {start: {line: 2, ch: 2}, end: {line: 2, ch: 21}}); }); it("should block comment, selection starts in code & ends in middle of line comment", function () { // #2342 myDocument.setText(lineCommentCode); myEditor.setSelection({line: 7, ch: 8}, {line: 7, ch: 20}); // stops at end of "post" var lines = lineCommentCode.split("\n"); lines[7] = " /*b(); // post*/ comment"; var expectedText = lines.join("\n"); testToggleBlock(expectedText, {start: {line: 7, ch: 10}, end: {line: 7, ch: 22}}); }); it("should block comment, selection starts in middle of code & ends at end of line comment", function () { // #2342 myDocument.setText(lineCommentCode); myEditor.setSelection({line: 7, ch: 9}, {line: 7, ch: 28}); var lines = lineCommentCode.split("\n"); lines[7] = " b/*(); // post comment*/"; var expectedText = lines.join("\n"); testToggleBlock(expectedText, {start: {line: 7, ch: 11}, end: {line: 7, ch: 30}}); }); it("should block comment, selection starts in code & ends at end of line comment", function () { // #2337 myDocument.setText(lineCommentCode); myEditor.setSelection({line: 7, ch: 8}, {line: 7, ch: 28}); var lines = lineCommentCode.split("\n"); lines[7] = " /*b(); // post comment*/"; var expectedText = lines.join("\n"); testToggleBlock(expectedText, {start: {line: 7, ch: 10}, end: {line: 7, ch: 30}}); }); it("should block comment, selection starts at col 0 of code & ends at end of line comment", function () { myDocument.setText(lineCommentCode); myEditor.setSelection({line: 7, ch: 0}, {line: 7, ch: 28}); var lines = lineCommentCode.split("\n"); lines[7] = "/* b(); // post comment*/"; var expectedText = lines.join("\n"); testToggleBlock(expectedText, {start: {line: 7, ch: 2}, end: {line: 7, ch: 30}}); }); it("should block comment, selection starts on line with line comment", function () { myDocument.setText(lineCommentCode); myEditor.setSelection({line: 4, ch: 0}, {line: 9, ch: 0}); var lines = lineCommentCode.split("\n"); lines.splice(9, 0, "*/"); lines.splice(4, 0, "/*"); var expectedText = lines.join("\n"); testToggleBlock(expectedText, {start: {line: 5, ch: 0}, end: {line: 10, ch: 0}}); }); it("should block comment, selection ends on line with line comment", function () { myDocument.setText(lineCommentCode); myEditor.setSelection({line: 10, ch: 0}, {line: 12, ch: 0}); var lines = lineCommentCode.split("\n"); lines.splice(12, 0, "*/"); lines.splice(10, 0, "/*"); var expectedText = lines.join("\n"); testToggleBlock(expectedText, {start: {line: 11, ch: 0}, end: {line: 13, ch: 0}}); }); it("should line uncomment, selection covers several line comments separated by whitespace", function () { myDocument.setText(lineCommentCode); myEditor.setSelection({line: 11, ch: 0}, {line: 14, ch: 0}); var lines = lineCommentCode.split("\n"); lines[11] = " Attached above"; lines[13] = " Final floating comment"; var expectedText = lines.join("\n"); testToggleBlock(expectedText, {start: {line: 11, ch: 0}, end: {line: 14, ch: 0}}); }); describe("with multiple selections", function () { it("should handle multiple selections where one of them is in a line comment", function () { // Add a line comment to line 1 var lines = defaultContent.split("\n"); lines[1] = "//" + lines[1]; myDocument.setText(lines.join("\n")); myEditor.setSelections([{start: {line: 1, ch: 4}, end: {line: 1, ch: 4}, primary: true}, {start: {line: 3, ch: 4}, end: {line: 3, ch: 12}}]); // Line 1 should no longer have a line comment, and line 3 should have a block comment. lines[1] = lines[1].substr(2); lines[3] = lines[3].substr(0, 4) + "/*" + lines[3].substr(4, 8) + "*/" + lines[3].substr(12); testToggleBlock(lines.join("\n"), [ {start: {line: 1, ch: 2}, end: {line: 1, ch: 2}, primary: true, reversed: false}, {start: {line: 3, ch: 6}, end: {line: 3, ch: 14}, primary: false, reversed: false} ]); }); it("should handle multiple selections where several of them are in the same line comment, preserving the ignored selections", function () { // Add a line comment to line 1 var lines = defaultContent.split("\n"); lines[1] = "//" + lines[1]; myDocument.setText(lines.join("\n")); myEditor.setSelections([{start: {line: 1, ch: 4}, end: {line: 1, ch: 4}, primary: true}, {start: {line: 1, ch: 6}, end: {line: 1, ch: 6}}]); // Line 1 should no longer have a line comment lines[1] = lines[1].substr(2); testToggleBlock(lines.join("\n"), [ {start: {line: 1, ch: 2}, end: {line: 1, ch: 2}, primary: true, reversed: false}, {start: {line: 1, ch: 4}, end: {line: 1, ch: 4}, primary: false, reversed: false} ]); }); }); }); // In cases where the language only supports block comments, the line comment/uncomment command may perform block comment/uncomment instead describe("Line comment auto-switching to block comment", function () { var cssContent = "div {\n" + " color: red;\n" + "}\n" + "\n" + "/*span {\n" + " color: blue;\n" + "}*/\n"; beforeEach(function () { setupFullEditor(cssContent, "css"); }); it("should block-comment entire line that cursor is in", function () { myEditor.setCursorPos(1, 4); var lines = cssContent.split("\n"); lines[1] = "/* color: red;*/"; var expectedText = lines.join("\n"); testToggleLine(expectedText, {line: 1, ch: 6}); }); it("should block-comment entire line that sub-line selection is in", function () { myEditor.setSelection({line: 1, ch: 4}, {line: 1, ch: 9}); var lines = cssContent.split("\n"); lines[1] = "/* color: red;*/"; var expectedText = lines.join("\n"); testToggleLine(expectedText, {start: {line: 1, ch: 6}, end: {line: 1, ch: 11}}); }); it("should block-comment full multi-line selection", function () { myEditor.setSelection({line: 0, ch: 0}, {line: 3, ch: 0}); var lines = cssContent.split("\n"); lines.splice(3, 0, "*/"); lines.splice(0, 0, "/*"); var expectedText = lines.join("\n"); testToggleLine(expectedText, {start: {line: 1, ch: 0}, end: {line: 4, ch: 0}}); }); it("should block-comment partial multi-line selection as if it were full", function () { myEditor.setSelection({line: 0, ch: 3}, {line: 1, ch: 10}); var lines = cssContent.split("\n"); lines.splice(2, 0, "*/"); lines.splice(0, 0, "/*"); var expectedText = lines.join("\n"); testToggleLine(expectedText, {start: {line: 1, ch: 3}, end: {line: 2, ch: 10}}); // range endpoints still align with same text }); it("should uncomment multi-line block comment selection, selected exactly", function () { myEditor.setSelection({line: 4, ch: 0}, {line: 6, ch: 3}); var lines = cssContent.split("\n"); lines[4] = "span {"; lines[6] = "}"; var expectedText = lines.join("\n"); testToggleLine(expectedText, {start: {line: 4, ch: 0}, end: {line: 6, ch: 1}}); }); it("should uncomment multi-line block comment selection, selected including trailing newline", function () { // #2339 myEditor.setSelection({line: 4, ch: 0}, {line: 7, ch: 0}); var lines = cssContent.split("\n"); lines[4] = "span {"; lines[6] = "}"; var expectedText = lines.join("\n"); testToggleLine(expectedText, {start: {line: 4, ch: 0}, end: {line: 7, ch: 0}}); }); it("should uncomment multi-line block comment selection, only start selected", function () { myEditor.setSelection({line: 4, ch: 0}, {line: 5, ch: 8}); var lines = cssContent.split("\n"); lines[4] = "span {"; lines[6] = "}"; var expectedText = lines.join("\n"); testToggleLine(expectedText, {start: {line: 4, ch: 0}, end: {line: 5, ch: 8}}); }); it("should uncomment multi-line block comment selection, only middle selected", function () { myEditor.setSelection({line: 5, ch: 0}, {line: 5, ch: 8}); var lines = cssContent.split("\n"); lines[4] = "span {"; lines[6] = "}"; var expectedText = lines.join("\n"); testToggleLine(expectedText, {start: {line: 5, ch: 0}, end: {line: 5, ch: 8}}); }); it("should uncomment multi-line block comment selection, only end selected", function () { // #2339 myEditor.setSelection({line: 5, ch: 8}, {line: 6, ch: 3}); var lines = cssContent.split("\n"); lines[4] = "span {"; lines[6] = "}"; var expectedText = lines.join("\n"); testToggleLine(expectedText, {start: {line: 5, ch: 8}, end: {line: 6, ch: 1}}); }); it("should uncomment multi-line block comment selection, only end selected, ends at EOF", function () { // remove trailing blank line, so end of "*/" is EOF (no newline afterward) myDocument.replaceRange("", {line: 6, ch: 3}, {line: 7, ch: 0}); var content = myDocument.getText(); myEditor.setSelection({line: 5, ch: 8}, {line: 6, ch: 3}); var lines = content.split("\n"); lines[4] = "span {"; lines[6] = "}"; var expectedText = lines.join("\n"); testToggleLine(expectedText, {start: {line: 5, ch: 8}, end: {line: 6, ch: 1}}); }); it("should uncomment multi-line block comment that cursor is in", function () { myEditor.setCursorPos(5, 4); var lines = cssContent.split("\n"); lines[4] = "span {"; lines[6] = "}"; var expectedText = lines.join("\n"); testToggleLine(expectedText, {line: 5, ch: 4}); }); }); describe("Comment/uncomment with mixed syntax modes with indentLineComment Disabled", function () { var htmlContent = "<html>\n" + " <head>\n" + " <style type='text/css'>\n" + " body {\n" + " font-size: 15px;\n" + " }\n" + " </style>\n" + " <script type='text/javascript'>\n" + " function foo() {\n" + " function bar() {\n" + " a();\n" + " }\n" + " }\n" + " </script>\n" + " </head>\n" + " <body>\n" + " <p>Hello</p>\n" + " <p>World</p>\n" + " </body>\n" + "</html>"; beforeEach(function () { setupFullEditor(htmlContent, "html"); PreferencesManager.set("indentLineComment", false); }); afterEach(function () { PreferencesManager.set("indentLineComment", shouldIndentLineComment); }); // Correct behavior for line and block comment commands it("should block comment/uncomment generic HTML code", function () { myEditor.setSelection({line: 1, ch: 4}, {line: 1, ch: 10}); var lines = htmlContent.split("\n"); lines[1] = " <!--<head>-->"; var expectedText = lines.join("\n"); testToggleBlock(expectedText, {start: { line: 1, ch: 8 }, end: {line: 1, ch: 14}}); }); it("should block comment/uncomment generic CSS code", function () { myEditor.setSelection({line: 4, ch: 16}, {line: 4, ch: 32}); var lines = htmlContent.split("\n"); lines[4] = " /*font-size: 15px;*/"; var expectedText = lines.join("\n"); testToggleBlock(expectedText, {start: {line: 4, ch: 18}, end: {line: 4, ch: 34}}); }); it("should line comment/uncomment generic JS code", function () { myEditor.setCursorPos(10, 0); var lines = htmlContent.split("\n"); lines[10] = "// a();"; var expectedText = lines.join("\n"); testToggleLine(expectedText, {line: 10, ch: 2}); // Uncomment testToggleLine(htmlContent, {line: 10, ch: 0}); }); it("should block comment/uncomment generic JS code", function () { myEditor.setSelection({line: 8, ch: 0}, {line: 13, ch: 0}); var lines = htmlContent.split("\n"); lines.splice(13, 0, "*/"); lines.splice(8, 0, "/*"); var expectedText = lines.join("\n"); testToggleBlock(expectedText, {start: {line: 9, ch: 0}, end: {line: 14, ch: 0}}); }); it("should HTML comment/uncomment around outside of <style> block", function () { myEditor.setSelection({line: 2, ch: 0}, {line: 7, ch: 0}); var lines = htmlContent.split("\n"); lines.splice(7, 0, "-->"); lines.splice(2, 0, "<!--"); var expectedText = lines.join("\n"); testToggleBlock(expectedText, {start: {line: 3, ch: 0}, end: {line: 8, ch: 0}}); }); it("shouldn't comment anything when selection mixes modes", function () { myEditor.setSelection({line: 3, ch: 0}, {line: 11, ch: 0}); testToggleBlock(htmlContent, {start: {line: 3, ch: 0}, end: {line: 11, ch: 0}}); }); describe("with multiple selections", function () { beforeEach(function () { PreferencesManager.set("indentLineComment", false); }); afterEach(function () { PreferencesManager.set("indentLineComment", shouldIndentLineComment); }); it("should handle multiple selections in different regions, toggling block selection in each", function () { myEditor.setSelections([{start: {line: 1, ch: 4}, end: {line: 1, ch: 10}}, {start: {line: 4, ch: 16}, end: {line: 4, ch: 32}}, {start: {line: 8, ch: 0}, end: {line: 13, ch: 0}}]); var lines = htmlContent.split("\n"); lines[1] = " <!--<head>-->"; lines[4] = " /*font-size: 15px;*/"; lines.splice(13, 0, "*/"); lines.splice(8, 0, "/*"); testToggleBlock(lines.join("\n"), [{start: {line: 1, ch: 8}, end: {line: 1, ch: 14}, primary: false, reversed: false}, {start: {line: 4, ch: 18}, end: {line: 4, ch: 34}, primary: false, reversed: false}, {start: {line: 9, ch: 0}, end: {line: 14, ch: 0}, primary: true, reversed: false}]); }); it("should handle multiple selections in different regions, toggling line selection (but falling back to block selection in HTML/CSS)", function () { myEditor.setSelections([{start: {line: 1, ch: 4}, end: {line: 1, ch: 10}}, {start: {line: 4, ch: 16}, end: {line: 4, ch: 32}}, {start: {line: 10, ch: 0}, end: {line: 10, ch: 0}}]); var lines = htmlContent.split("\n"); lines[1] = "<!-- <head>-->"; lines[4] = "/* font-size: 15px;*/"; lines[10] = "// a();"; testToggleLine(lines.join("\n"), [{start: {line: 1, ch: 8}, end: {line: 1, ch: 14}, primary: false, reversed: false}, {start: {line: 4, ch: 18}, end: {line: 4, ch: 34}, primary: false, reversed: false}, {start: {line: 10, ch: 2}, end: {line: 10, ch: 2}, primary: true, reversed: false}]); }); it("shouldn't comment anything in a mixed-mode selection, but should track it properly and comment the other selections", function () { // Select the whole HTML tag so it will actually insert a line, causing other selections to get fixed up. myEditor.setSelections([{start: {line: 1, ch: 0}, end: {line: 2, ch: 0}}, {start: {line: 5, ch: 0}, end: {line: 7, ch: 0}, reversed: true, primary: true}, {start: {line: 8, ch: 0}, end: {line: 13, ch: 0}}]); var lines = htmlContent.split("\n"); lines.splice(13, 0, "*/"); lines.splice(8, 0, "/*"); lines.splice(2, 0, "-->"); lines.splice(1, 0, "<!--"); testToggleBlock(lines.join("\n"), [{start: {line: 2, ch: 0}, end: {line: 3, ch: 0}, primary: false, reversed: false}, {start: {line: 7, ch: 0}, end: {line: 9, ch: 0}, primary: true, reversed: true}, {start: {line: 11, ch: 0}, end: {line: 16, ch: 0}, primary: false, reversed: false}]); }); }); }); describe("Comment/uncomment with mixed syntax modes with indentLineComment Enabled", function () { var htmlContent = "<html>\n" + " <head>\n" + " <style type='text/css'>\n" + " body {\n" + " font-size: 15px;\n" + " }\n" + " </style>\n" + " <script type='text/javascript'>\n" + " function foo() {\n" + " function bar() {\n" + " a();\n" + " }\n" + " }\n" + " </script>\n" + " </head>\n" + " <body>\n" + " <p>Hello</p>\n" + " <p>World</p>\n" + " </body>\n" + "</html>"; beforeEach(function () { setupFullEditor(htmlContent, "html"); PreferencesManager.set("indentLineComment", true); }); afterEach(function () { PreferencesManager.set("indentLineComment", shouldIndentLineComment); }); it("should line comment/uncomment generic JS code", function () { myEditor.setCursorPos(10, 0); var lines = htmlContent.split("\n"); lines[10] = " //a();"; var expectedText = lines.join("\n"); testToggleLine(expectedText, {line: 10, ch: 0}); // Uncomment testToggleLine(htmlContent, {line: 10, ch: 0}); }); it("should line comment/uncomment and indent HTML code", function () { myEditor.setCursorPos(16, 8); var lines = htmlContent.split("\n"); lines[16] = " <!--<p>Hello</p>-->"; var expectedText = lines.join("\n"); testToggleLine(expectedText, {line: 16, ch: 12}); // Uncomment testToggleLine(htmlContent, {line: 16, ch: 8}); }); describe("with multiple selections", function () { beforeEach(function () { PreferencesManager.set("indentLineComment", true); }); afterEach(function () { PreferencesManager.set("indentLineComment", shouldIndentLineComment); }); it("should handle multiple selections in different regions, toggling line selection (but falling back to block selection in HTML/CSS)", function () { myEditor.setSelections([{start: {line: 1, ch: 4}, end: {line: 1, ch: 10}}, {start: {line: 4, ch: 16}, end: {line: 4, ch: 32}}, {start: {line: 10, ch: 0}, end: {line: 10, ch: 0}}]); var lines = htmlContent.split("\n"); lines[1] = " <!--<head>-->"; lines[4] = " /*font-size: 15px;*/"; lines[10] = " //a();"; testToggleLine(lines.join("\n"), [{start: {line: 1, ch: 8 }, end: {line: 1, ch: 14 }, reversed: false, primary: false}, {start: {line: 4, ch: 18 }, end: {line: 4, ch: 34 }, reversed: false, primary: false}, {start: {line: 10, ch: 0 }, end: {line: 10, ch: 0 }, reversed: false, primary: true}]); }); }); }); describe("Comment/uncomment on languages with equal prefix and suffix and a line prefix being prefix of a block prefix/suffix", function () { // Define a new CoffeeScript language for testing purposes LanguageManager.defineLanguage("coffeescript2", { "name": "CoffeeScript2", "mode": "coffeescript", "fileExtensions": ["coffee2"], "blockComment": ["###", "###"], "lineComment": ["#"] }); var coffeeContent = "foo = 42\n" + "bar = true\n" + "baz = \"hello\"\n" + "number = -42\n" + "if bar square = (x) -> x * x"; function getContentCommented(startLine, endLine, content) { var lines = (content || coffeeContent).split("\n"); lines.splice(endLine, 0, "###"); lines.splice(startLine, 0, "###"); return lines.join("\n"); } beforeEach(function () { setupFullEditor(coffeeContent, "coffeescript2"); }); it("should block comment/uncomment selecting part of lines", function () { myEditor.setSelection({line: 2, ch: 2}, {line: 3, ch: 5}); var lines = coffeeContent.split("\n"); lines[2] = "ba###z = \"hello\""; lines[3] = "numbe###r = -42"; var expectedText = lines.join("\n"); testToggleBlock(expectedText, {start: {line: 2, ch: 5}, end: {line: 3, ch: 5}}); }); it("should block comment/uncomment selecting full lines", function () { myEditor.setSelection({line: 1, ch: 0}, {line: 3, ch: 0}); var expectedText = getContentCommented(1, 3); testToggleBlock(expectedText, {start: {line: 2, ch: 0}, end: {line: 4, ch: 0}}); }); it("should block uncomment when selecting the prefix and suffix", function () { myDocument.setText(getContentCommented(1, 3)); myEditor.setSelection({line: 1, ch: 0}, {line: 5, ch: 0}); testToggleBlock(coffeeContent, {start: {line: 1, ch: 0}, end: {line: 3, ch: 0}}); }); it("should block uncomment when selecting only the prefix", function () { myDocument.setText(getContentCommented(1, 3)); myEditor.setSelection({line: 1, ch: 0}, {line: 2, ch: 0}); testToggleBlock(coffeeContent, {start: {line: 1, ch: 0}, end: {line: 1, ch: 0}}); }); it("should block uncomment when selecting only the suffix", function () { myDocument.setText(getContentCommented(1, 3)); myEditor.setSelection({line: 4, ch: 0}, {line: 5, ch: 0}); testToggleBlock(coffeeContent, {start: {line: 3, ch: 0}, end: {line: 3, ch: 0}}); }); it("should do nothing when selecting from a suffix to a prefix", function () { var expectedText = getContentCommented(0, 1, getContentCommented(4, 5)); myDocument.setText(expectedText); myEditor.setSelection({line: 2, ch: 0}, {line: 7, ch: 0}); testToggleBlock(expectedText, {start: {line: 2, ch: 0}, end: {line: 7, ch: 0}}); }); it("should block uncomment with line comments around the block comment", function () { var lines = coffeeContent.split("\n"); lines[0] = "#foo = 42"; lines[3] = "#number = -42"; var expectedText = lines.join("\n"); myDocument.setText(getContentCommented(1, 3, expectedText)); myEditor.setSelection({line: 1, ch: 0}, {line: 3, ch: 0}); testToggleBlock(expectedText, {start: {line: 1, ch: 0}, end: {line: 2, ch: 0}}); }); it("should block uncomment when the lines inside the block comment are line commented", function () { var lines = coffeeContent.split("\n"); lines[2] = "#baz = \"hello\""; var expectedText = lines.join("\n"); myDocument.setText(getContentCommented(1, 3, expectedText)); myEditor.setSelection({line: 3, ch: 0}, {line: 4, ch: 0}); testToggleBlock(expectedText, {start: {line: 2, ch: 0}, end: {line: 3, ch: 0}}); }); it("should block uncomment a second block comment", function () { var expectedText = getContentCommented(0, 1); myDocument.setText(getContentCommented(6, 7, expectedText)); myEditor.setSelection({line: 7, ch: 0}, {line: 8, ch: 0}); testToggleBlock(expectedText + "\n", {start: {line: 6, ch: 0}, end: {line: 7, ch: 0}}); }); it("should block uncomment with line comments in between the block comments", function () { var lines = coffeeContent.split("\n"); lines[1] = "#bar = true"; lines[2] = "#baz = \"hello\""; lines[3] = "#number = -42"; var expectedText = getContentCommented(0, 1, lines.join("\n")); myDocument.setText(getContentCommented(6, 7, expectedText)); myEditor.setSelection({line: 7, ch: 0}, {line: 8, ch: 0}); testToggleBlock(expectedText + "\n", {start: {line: 6, ch: 0}, end: {line: 7, ch: 0}}); }); it("should block comment on an empty line around comments", function () { var lines = coffeeContent.split("\n"); lines[2] = "###baz = \"hello\"###"; lines[3] = ""; lines[4] = "#number = -42"; var text = lines.join("\n"); lines[3] = "######"; var expectedText = lines.join("\n"); myDocument.setText(text); myEditor.setCursorPos(3, 0); testToggleBlock(expectedText, {line: 3, ch: 3}); }); it("should block uncomment on an empty line inside a block comment", function () { var lines = coffeeContent.split("\n"); lines[1] = "###bar = true"; lines[2] = ""; lines[3] = "number = -42###"; var text = lines.join("\n"); lines = coffeeContent.split("\n"); lines[2] = ""; var expectedText = lines.join("\n"); myDocument.setText(text); myEditor.setCursorPos(2, 0); testToggleBlock(expectedText, {line: 2, ch: 0}); }); it("should line uncomment on line comments around a block comment", function () { var lines = getContentCommented(1, 3).split("\n"); lines[5] = "#number = -42"; var text = lines.join("\n"); lines = text.split("\n"); lines[5] = "number = -42"; var expectedText = lines.join("\n"); myDocument.setText(text); myEditor.setSelection({line: 5, ch: 0}, {line: 6, ch: 0}); testToggleBlock(expectedText, {start: {line: 5, ch: 0}, end: {line: 6, ch: 0}}); }); it("should line comment block commented lines", function () { var lines = coffeeContent.split("\n"); lines[2] = "###baz = \"hello\"###"; var text = lines.join("\n"); lines = text.split("\n"); lines[2] = "####baz = \"hello\"###"; var expectedText = lines.join("\n"); myDocument.setText(text); myEditor.setSelection({line: 2, ch: 0}, {line: 2, ch: 5}); testToggleLine(expectedText, {start: {line: 2, ch: 0}, end: {line: 2, ch: 6}}); }); it("should line comment in block comment prefix or sufix starting lines", function () { var lines = coffeeContent.split("\n"); lines[0] = "#foo = 42"; lines[3] = "#number = -42"; var text = getContentCommented(1, 3, lines.join("\n")); myDocument.setText(text); lines = text.split("\n"); lines[0] = "##foo = 42"; lines[1] = "####"; var expectedText = lines.join("\n"); myEditor.setSelection({line: 0, ch: 0}, {line: 2, ch: 0}); testToggleLine(expectedText, {start: {line: 0, ch: 0}, end: {line: 2, ch: 0}}); lines[4] = "####"; lines[5] = "##number = -42"; expectedText = lines.join("\n"); myEditor.setSelection({line: 4, ch: 0}, {line: 6, ch: 0}); testToggleLine(expectedText, {start: {line: 4, ch: 0}, end: {line: 6, ch: 0}}); }); }); describe("Duplicate", function () { beforeEach(setupFullEditor); it("should duplicate whole line if no selection", function () { // place cursor in middle of line 1 myEditor.setCursorPos(1, 10); CommandManager.execute(Commands.EDIT_DUPLICATE, myEditor); var lines = defaultContent.split("\n"); lines.splice(1, 0, " function bar() {"); var expectedText = lines.join("\n"); expect(myDocument.getText()).toEqual(expectedText); expectCursorAt({line: 2, ch: 10}); }); it("should duplicate line + \n if selected line is at end of file", function () { var lines = defaultContent.split("\n"), len = lines.length; // place cursor at the beginning of the last line myEditor.setCursorPos(len - 1, 0); CommandManager.execute(Commands.EDIT_DUPLICATE, myEditor); lines.push("}"); var expectedText = lines.join("\n"); expect(myDocument.getText()).toEqual(expectedText); expectCursorAt({line: len, ch: 0}); }); it("should duplicate first line", function () { // place cursor at start of line 0 myEditor.setCursorPos(0, 0); CommandManager.execute(Commands.EDIT_DUPLICATE, myEditor); var lines = defaultContent.split("\n"); lines.splice(0, 0, "function foo() {"); var expectedText = lines.join("\n"); expect(myDocument.getText()).toEqual(expectedText); expectCursorAt({line: 1, ch: 0}); }); it("should duplicate empty line", function () { // place cursor on line 6 myEditor.setCursorPos(6, 0); CommandManager.execute(Commands.EDIT_DUPLICATE, myEditor); var lines = defaultContent.split("\n"); lines.splice(6, 0, ""); var expectedText = lines.join("\n"); expect(myDocument.getText()).toEqual(expectedText); expectCursorAt({line: 7, ch: 0}); }); it("should duplicate selection within a line", function () { // select "bar" on line 1 myEditor.setSelection({line: 1, ch: 13}, {line: 1, ch: 16}); CommandManager.execute(Commands.EDIT_DUPLICATE, myEditor); var lines = defaultContent.split("\n"); lines[1] = " function barbar() {"; var expectedText = lines.join("\n"); expect(myDocument.getText()).toEqual(expectedText); expectSelection({start: {line: 1, ch: 16}, end: {line: 1, ch: 19}}); }); it("should duplicate when entire line selected, excluding newline", function () { // select all of line 1, EXcluding trailing \n myEditor.setSelection({line: 1, ch: 0}, {line: 1, ch: 20}); CommandManager.execute(Commands.EDIT_DUPLICATE, myEditor); var lines = defaultContent.split("\n"); lines[1] = " function bar() { function bar() {"; var expectedText = lines.join("\n"); expect(myDocument.getText()).toEqual(expectedText); expectSelection({start: {line: 1, ch: 20}, end: {line: 1, ch: 40}}); }); it("should duplicate when entire line selected, including newline", function () { // select all of line 1, INcluding trailing \n myEditor.setSelection({line: 1, ch: 0}, {line: 2, ch: 0}); CommandManager.execute(Commands.EDIT_DUPLICATE, myEditor); var lines = defaultContent.split("\n"); lines.splice(1, 0, " function bar() {"); var expectedText = lines.join("\n"); expect(myDocument.getText()).toEqual(expectedText); expectSelection({start: {line: 2, ch: 0}, end: {line: 3, ch: 0}}); }); it("should duplicate when multiple lines selected", function () { // select lines 1-3 myEditor.setSelection({line: 1, ch: 0}, {line: 4, ch: 0}); CommandManager.execute(Commands.EDIT_DUPLICATE, myEditor); var lines = defaultContent.split("\n"); lines.splice(1, 0, " function bar() {", " ", " a();"); var expectedText = lines.join("\n"); expect(myDocument.getText()).toEqual(expectedText); expectSelection({start: {line: 4, ch: 0}, end: {line: 7, ch: 0}}); }); it("should duplicate selection crossing line boundary", function () { // select from middle of line 1 to middle of line 3 myEditor.setSelection({line: 1, ch: 13}, {line: 3, ch: 11}); CommandManager.execute(Commands.EDIT_DUPLICATE, myEditor); var lines = defaultContent.split("\n"); lines.splice(1, 3, " function bar() {", " ", " a()bar() {", " ", " a();"); var expectedText = lines.join("\n"); expect(myDocument.getText()).toEqual(expectedText); expectSelection({start: {line: 3, ch: 11}, end: {line: 5, ch: 11}}); }); it("should duplicate after select all", function () { myEditor.setSelection({line: 0, ch: 0}, {line: 7, ch: 1}); CommandManager.execute(Commands.EDIT_DUPLICATE, myEditor); var expectedText = defaultContent + defaultContent; expect(myDocument.getText()).toEqual(expectedText); expectSelection({start: {line: 7, ch: 1}, end: {line: 14, ch: 1}}); }); describe("with multiple selections", function () { it("should duplicate multiple lines containing cursors", function () { myEditor.setSelections([{start: {line: 1, ch: 3}, end: {line: 1, ch: 3}}, {start: {line: 3, ch: 3}, end: {line: 3, ch: 3}}]); CommandManager.execute(Commands.EDIT_DUPLICATE, myEditor); var lines = defaultContent.split("\n"); lines.splice(4, 0, lines[3]); lines.splice(2, 0, lines[1]); expect(myDocument.getText()).toEqual(lines.join("\n")); expectSelections([{start: {line: 2, ch: 3}, end: {line: 2, ch: 3}, primary: false, reversed: false}, {start: {line: 5, ch: 3}, end: {line: 5, ch: 3}, primary: true, reversed: false}]); }); it("should not duplicate the same line multiple times", function () { myEditor.setSelections([{start: {line: 1, ch: 3}, end: {line: 1, ch: 3}}, {start: {line: 1, ch: 6}, end: {line: 1, ch: 6}}, {start: {line: 3, ch: 3}, end: {line: 3, ch: 3}}]); CommandManager.execute(Commands.EDIT_DUPLICATE, myEditor); var lines = defaultContent.split("\n"); lines.splice(4, 0, lines[3]); lines.splice(2, 0, lines[1]); expect(myDocument.getText()).toEqual(lines.join("\n")); expectSelections([{start: {line: 2, ch: 3}, end: {line: 2, ch: 3}, primary: false, reversed: false}, {start: {line: 2, ch: 6}, end: {line: 2, ch: 6}, primary: false, reversed: false}, {start: {line: 5, ch: 3}, end: {line: 5, ch: 3}, primary: true, reversed: false}]); }); it("should duplicate multiple range selections", function () { // select "bar" on line 1, cursor on line 2, and "a()" on line 3 myEditor.setSelections([{start: {line: 1, ch: 13}, end: {line: 1, ch: 16}}, {start: {line: 3, ch: 8}, end: {line: 3, ch: 11}}]); CommandManager.execute(Commands.EDIT_DUPLICATE, myEditor); var lines = defaultContent.split("\n"); lines[1] = " function barbar() {"; lines[3] = " a()a();"; var expectedText = lines.join("\n"); expect(myDocument.getText()).toEqual(expectedText); expectSelections([{start: {line: 1, ch: 16}, end: {line: 1, ch: 19}, primary: false, reversed: false}, {start: {line: 3, ch: 11}, end: {line: 3, ch: 14}, primary: true, reversed: false}]); }); it("should duplicate a mix of cursors and ranges", function () { // select "bar" on line 1, cursor on line 2, and "a()" on line 3 myEditor.setSelections([{start: {line: 1, ch: 13}, end: {line: 1, ch: 16}}, {start: {line: 2, ch: 3}, end: {line: 2, ch: 3}}, {start: {line: 3, ch: 8}, end: {line: 3, ch: 11}}]); CommandManager.execute(Commands.EDIT_DUPLICATE, myEditor); var lines = defaultContent.split("\n"); lines[1] = " function barbar() {"; lines[3] = " a()a();"; lines.splice(3, 0, lines[2]); var expectedText = lines.join("\n"); expect(myDocument.getText()).toEqual(expectedText); expectSelections([{start: {line: 1, ch: 16}, end: {line: 1, ch: 19}, primary: false, reversed: false}, {start: {line: 3, ch: 3}, end: {line: 3, ch: 3}, primary: false, reversed: false}, {start: {line: 4, ch: 11}, end: {line: 4, ch: 14}, primary: true, reversed: false}]); }); it("should duplicate line first, then range, if both a cursor and range are on the same line", function () { myEditor.setSelections([{start: {line: 1, ch: 3}, end: {line: 1, ch: 3}}, {start: {line: 1, ch: 13}, end: {line: 1, ch: 16}}]); CommandManager.execute(Commands.EDIT_DUPLICATE, myEditor); var lines = defaultContent.split("\n"); lines.splice(2, 0, " function barbar() {"); expect(myDocument.getText()).toEqual(lines.join("\n")); expectSelections([{start: {line: 2, ch: 3}, end: {line: 2, ch: 3}, primary: false, reversed: false}, {start: {line: 2, ch: 16}, end: {line: 2, ch: 19}, primary: true, reversed: false}]); }); }); }); describe("Move Lines Up/Down", function () { function swapLines(lines, swaps) { _.each(swaps, function (swap) { var temp = lines[swap[0]], i; for (i = 0; i < swap.length - 1; i++) { lines[swap[i]] = lines[swap[i + 1]]; } lines[swap[swap.length - 1]] = temp; }); } beforeEach(setupFullEditor); it("should move whole line up if no selection", function () { // place cursor in middle of line 1 myEditor.setCursorPos(1, 10); CommandManager.execute(Commands.EDIT_LINE_UP, myEditor); var lines = defaultContent.split("\n"); swapLines(lines, [[0, 1]]); var expectedText = lines.join("\n"); expect(myDocument.getText()).toEqual(expectedText); expectCursorAt({line: 0, ch: 10}); }); it("should move whole line down if no selection", function () { // place cursor in middle of line 1 myEditor.setCursorPos(1, 10); CommandManager.execute(Commands.EDIT_LINE_DOWN, myEditor); var lines = defaultContent.split("\n"); swapLines(lines, [[2, 1]]); var expectedText = lines.join("\n"); expect(myDocument.getText()).toEqual(expectedText); expectCursorAt({line: 2, ch: 10}); }); it("shouldn't move up first line", function () { // place cursor at start of line 0 myEditor.setCursorPos(0, 0); CommandManager.execute(Commands.EDIT_LINE_UP, myEditor); expect(myDocument.getText()).toEqual(defaultContent); expectCursorAt({line: 0, ch: 0}); }); it("shouldn't move down last line", function () { var lines = defaultContent.split("\n"), len = lines.length; // place cursor at the beginning of the last line myEditor.setCursorPos(len - 1, 0); CommandManager.execute(Commands.EDIT_LINE_DOWN, myEditor); var expectedText = lines.join("\n"); expect(myDocument.getText()).toEqual(expectedText); expectCursorAt({line: len - 1, ch: 0}); }); it("should move up empty line", function () { // place cursor on line 6 myEditor.setCursorPos(6, 0); CommandManager.execute(Commands.EDIT_LINE_UP, myEditor); var lines = defaultContent.split("\n"); swapLines(lines, [[5, 6]]); var expectedText = lines.join("\n"); expect(myDocument.getText()).toEqual(expectedText); expectCursorAt({line: 5, ch: 0}); }); it("should move down empty line", function () { // place cursor on line 6 myEditor.setCursorPos(6, 0); CommandManager.execute(Commands.EDIT_LINE_DOWN, myEditor); var lines = defaultContent.split("\n"); swapLines(lines, [[7, 6]]); var expectedText = lines.join("\n"); expect(myDocument.getText()).toEqual(expectedText); expectCursorAt({line: 7, ch: 0}); }); it("should move up when entire line selected, excluding newline", function () { // select all of line 1, EXcluding trailing \n myEditor.setSelection({line: 1, ch: 0}, {line: 1, ch: 20}); CommandManager.execute(Commands.EDIT_LINE_UP, myEditor); var lines = defaultContent.split("\n"); swapLines(lines, [[0, 1]]); var expectedText = lines.join("\n"); expect(myDocument.getText()).toEqual(expectedText); expectSelection({start: {line: 0, ch: 0}, end: {line: 0, ch: 20}}); }); it("should move down when entire line selected, excluding newline", function () { // select all of line 1, EXcluding trailing \n myEditor.setSelection({line: 1, ch: 0}, {line: 1, ch: 20}); CommandManager.execute(Commands.EDIT_LINE_DOWN, myEditor); var lines = defaultContent.split("\n"); swapLines(lines, [[2, 1]]); var expectedText = lines.join("\n"); expect(myDocument.getText()).toEqual(expectedText); expectSelection({start: {line: 2, ch: 0}, end: {line: 2, ch: 20}}); }); it("should move up when entire line selected, including newline", function () { // select all of line 1, INcluding trailing \n myEditor.setSelection({line: 1, ch: 0}, {line: 2, ch: 0}); CommandManager.execute(Commands.EDIT_LINE_UP, myEditor); var lines = defaultContent.split("\n"); swapLines(lines, [[0, 1]]); var expectedText = lines.join("\n"); expect(myDocument.getText()).toEqual(expectedText); expectSelection({start: {line: 0, ch: 0}, end: {line: 1, ch: 0}}); }); it("should move down when entire line selected, including newline", function () { // select all of line 1, INcluding trailing \n myEditor.setSelection({line: 1, ch: 0}, {line: 2, ch: 0}); CommandManager.execute(Commands.EDIT_LINE_DOWN, myEditor); var lines = defaultContent.split("\n"); swapLines(lines, [[2, 1]]); var expectedText = lines.join("\n"); expect(myDocument.getText()).toEqual(expectedText); expectSelection({start: {line: 2, ch: 0}, end: {line: 3, ch: 0}}); }); it("should move up when multiple lines selected", function () { // select lines 2-3 myEditor.setSelection({line: 2, ch: 0}, {line: 4, ch: 0}); CommandManager.execute(Commands.EDIT_LINE_UP, myEditor); var lines = defaultContent.split("\n"); swapLines(lines, [[1, 2, 3]]); var expectedText = lines.join("\n"); expect(myDocument.getText()).toEqual(expectedText); expectSelection({start: {line: 1, ch: 0}, end: {line: 3, ch: 0}}); }); it("should move down when multiple lines selected", function () { // select lines 2-3 myEditor.setSelection({line: 2, ch: 0}, {line: 4, ch: 0}); CommandManager.execute(Commands.EDIT_LINE_DOWN, myEditor); var lines = defaultContent.split("\n"); swapLines(lines, [[4, 3, 2]]); var expectedText = lines.join("\n"); expect(myDocument.getText()).toEqual(expectedText); expectSelection({start: {line: 3, ch: 0}, end: {line: 5, ch: 0}}); }); it("should move up selection crossing line boundary", function () { // select from middle of line 2 to middle of line 3 myEditor.setSelection({line: 2, ch: 8}, {line: 3, ch: 11}); CommandManager.execute(Commands.EDIT_LINE_UP, myEditor); var lines = defaultContent.split("\n"); swapLines(lines, [[1, 2, 3]]); var expectedText = lines.join("\n"); expect(myDocument.getText()).toEqual(expectedText); expectSelection({start: {line: 1, ch: 8}, end: {line: 2, ch: 11}}); }); it("should move down selection crossing line boundary", function () { // select from middle of line 2 to middle of line 3 myEditor.setSelection({line: 2, ch: 8}, {line: 3, ch: 11}); CommandManager.execute(Commands.EDIT_LINE_DOWN, myEditor); var lines = defaultContent.split("\n"); swapLines(lines, [[4, 3, 2]]); var expectedText = lines.join("\n"); expect(myDocument.getText()).toEqual(expectedText); expectSelection({start: {line: 3, ch: 8}, end: {line: 4, ch: 11}}); }); it("should move the last line up", function () { // place cursor in last line myEditor.setCursorPos(7, 0); CommandManager.execute(Commands.EDIT_LINE_UP, myEditor); var lines = defaultContent.split("\n"); swapLines(lines, [[6, 7]]); var expectedText = lines.join("\n"); expect(myDocument.getText()).toEqual(expectedText); expectCursorAt({line: 6, ch: 0}); }); it("should move the first line down", function () { // place cursor in first line myEditor.setCursorPos(0, 0); CommandManager.execute(Commands.EDIT_LINE_DOWN, myEditor); var lines = defaultContent.split("\n"); swapLines(lines, [[1, 0]]); var expectedText = lines.join("\n"); expect(myDocument.getText()).toEqual(expectedText); expectCursorAt({line: 1, ch: 0}); }); it("should move the last lines up", function () { // select lines 6-7 myEditor.setSelection({line: 6, ch: 0}, {line: 7, ch: 1}); CommandManager.execute(Commands.EDIT_LINE_UP, myEditor); var lines = defaultContent.split("\n"); swapLines(lines, [[5, 6, 7]]); var expectedText = lines.join("\n"); expect(myDocument.getText()).toEqual(expectedText); expectSelection({start: {line: 5, ch: 0}, end: {line: 6, ch: 1}}); }); it("should move the first lines down", function () { // select lines 0-1 myEditor.setSelection({line: 0, ch: 0}, {line: 2, ch: 0}); CommandManager.execute(Commands.EDIT_LINE_DOWN, myEditor); var lines = defaultContent.split("\n"); swapLines(lines, [[2, 1, 0]]); var expectedText = lines.join("\n"); expect(myDocument.getText()).toEqual(expectedText); expectSelection({start: {line: 1, ch: 0}, end: {line: 3, ch: 0}}); }); it("shouldn't move up after select all", function () { myEditor.setSelection({line: 0, ch: 0}, {line: 7, ch: 1}); CommandManager.execute(Commands.EDIT_LINE_UP, myEditor); expect(myDocument.getText()).toEqual(defaultContent); expectSelection({start: {line: 0, ch: 0}, end: {line: 7, ch: 1}}); }); it("shouldn't move down after select all", function () { myEditor.setSelection({line: 0, ch: 0}, {line: 7, ch: 1}); CommandManager.execute(Commands.EDIT_LINE_DOWN, myEditor); expect(myDocument.getText()).toEqual(defaultContent); expectSelection({start: {line: 0, ch: 0}, end: {line: 7, ch: 1}}); }); describe("with multiple selections", function () { it("should move discontiguous lines up", function () { myEditor.setSelections([{start: {line: 1, ch: 4}, end: {line: 1, ch: 4}}, {start: {line: 3, ch: 4}, end: {line: 3, ch: 4}}, {start: {line: 5, ch: 4}, end: {line: 5, ch: 4}}]); CommandManager.execute(Commands.EDIT_LINE_UP, myEditor); var lines = defaultContent.split("\n"); swapLines(lines, [[0, 1], [2, 3], [4, 5]]); expect(myDocument.getText()).toEqual(lines.join("\n")); expectSelections([{start: {line: 0, ch: 4}, end: {line: 0, ch: 4}, primary: false, reversed: false}, {start: {line: 2, ch: 4}, end: {line: 2, ch: 4}, primary: false, reversed: false}, {start: {line: 4, ch: 4}, end: {line: 4, ch: 4}, primary: true, reversed: false}]); }); it("should move discontiguous lines down", function () { myEditor.setSelections([{start: {line: 1, ch: 4}, end: {line: 1, ch: 4}}, {start: {line: 3, ch: 4}, end: {line: 3, ch: 4}}, {start: {line: 5, ch: 4}, end: {line: 5, ch: 4}}]); CommandManager.execute(Commands.EDIT_LINE_DOWN, myEditor); var lines = defaultContent.split("\n"); swapLines(lines, [[2, 1], [4, 3], [6, 5]]); expect(myDocument.getText()).toEqual(lines.join("\n")); expectSelections([{start: {line: 2, ch: 4}, end: {line: 2, ch: 4}, primary: false, reversed: false}, {start: {line: 4, ch: 4}, end: {line: 4, ch: 4}, primary: false, reversed: false}, {start: {line: 6, ch: 4}, end: {line: 6, ch: 4}, primary: true, reversed: false}]); }); it("should move adjacent single lines with multiple selections up together", function () { myEditor.setSelections([{start: {line: 1, ch: 4}, end: {line: 1, ch: 4}}, {start: {line: 2, ch: 4}, end: {line: 2, ch: 4}}]); CommandManager.execute(Commands.EDIT_LINE_UP, myEditor); var lines = defaultContent.split("\n"); swapLines(lines, [[0, 1, 2]]); expect(myDocument.getText()).toEqual(lines.join("\n")); expectSelections([{start: {line: 0, ch: 4}, end: {line: 0, ch: 4}, primary: false, reversed: false}, {start: {line: 1, ch: 4}, end: {line: 1, ch: 4}, primary: true, reversed: false}]); }); it("should move adjacent single lines with multiple selections down together", function () { myEditor.setSelections([{start: {line: 1, ch: 4}, end: {line: 1, ch: 4}}, {start: {line: 2, ch: 4}, end: {line: 2, ch: 4}}]); CommandManager.execute(Commands.EDIT_LINE_DOWN, myEditor); var lines = defaultContent.split("\n"); swapLines(lines, [[3, 2, 1]]); expect(myDocument.getText()).toEqual(lines.join("\n")); expectSelections([{start: {line: 2, ch: 4}, end: {line: 2, ch: 4}, primary: false, reversed: false}, {start: {line: 3, ch: 4}, end: {line: 3, ch: 4}, primary: true, reversed: false}]); }); it("should move adjacent blocks of lines with multiple selections up together", function () { myEditor.setSelections([{start: {line: 1, ch: 5}, end: {line: 2, ch: 6}}, {start: {line: 3, ch: 3}, end: {line: 3, ch: 3}}]); CommandManager.execute(Commands.EDIT_LINE_UP, myEditor); var lines = defaultContent.split("\n"); swapLines(lines, [[0, 1, 2, 3]]); expect(myDocument.getText()).toEqual(lines.join("\n")); expectSelections([{start: {line: 0, ch: 5}, end: {line: 1, ch: 6}, primary: false, reversed: false}, {start: {line: 2, ch: 3}, end: {line: 2, ch: 3}, primary: true, reversed: false}]); }); it("should move adjacent blocks of lines with multiple selections down together", function () { myEditor.setSelections([{start: {line: 1, ch: 5}, end: {line: 2, ch: 6}}, {start: {line: 3, ch: 3}, end: {line: 3, ch: 3}}]); CommandManager.execute(Commands.EDIT_LINE_DOWN, myEditor); var lines = defaultContent.split("\n"); swapLines(lines, [[4, 3, 2, 1]]); expect(myDocument.getText()).toEqual(lines.join("\n")); expectSelections([{start: {line: 2, ch: 5}, end: {line: 3, ch: 6}, primary: false, reversed: false}, {start: {line: 4, ch: 3}, end: {line: 4, ch: 3}, primary: true, reversed: false}]); }); it("should move each line up only once if there are multiple cursors/selections on the same line, but preserve the selections", function () { myEditor.setSelections([{start: {line: 1, ch: 4}, end: {line: 1, ch: 4}}, {start: {line: 1, ch: 6}, end: {line: 1, ch: 6}, primary: true}, {start: {line: 3, ch: 4}, end: {line: 3, ch: 4}}, {start: {line: 3, ch: 5}, end: {line: 3, ch: 6}, reversed: true}]); CommandManager.execute(Commands.EDIT_LINE_UP, myEditor); var lines = defaultContent.split("\n"); swapLines(lines, [[0, 1], [2, 3]]); expect(myDocument.getText()).toEqual(lines.join("\n")); expectSelections([{start: {line: 0, ch: 4}, end: {line: 0, ch: 4}, primary: false, reversed: false}, {start: {line: 0, ch: 6}, end: {line: 0, ch: 6}, primary: true, reversed: false}, {start: {line: 2, ch: 4}, end: {line: 2, ch: 4}, primary: false, reversed: false}, {start: {line: 2, ch: 5}, end: {line: 2, ch: 6}, primary: false, reversed: true}]); }); it("should move each line down only once if there are multiple cursors/selections on the same line, but preserve the selections", function () { myEditor.setSelections([{start: {line: 1, ch: 4}, end: {line: 1, ch: 4}}, {start: {line: 1, ch: 6}, end: {line: 1, ch: 6}, primary: true}, {start: {line: 3, ch: 4}, end: {line: 3, ch: 4}}, {start: {line: 3, ch: 5}, end: {line: 3, ch: 6}, reversed: true}]); CommandManager.execute(Commands.EDIT_LINE_DOWN, myEditor); var lines = defaultContent.split("\n"); swapLines(lines, [[2, 1], [4, 3]]); expect(myDocument.getText()).toEqual(lines.join("\n")); expectSelections([{start: {line: 2, ch: 4}, end: {line: 2, ch: 4}, primary: false, reversed: false}, {start: {line: 2, ch: 6}, end: {line: 2, ch: 6}, primary: true, reversed: false}, {start: {line: 4, ch: 4}, end: {line: 4, ch: 4}, primary: false, reversed: false}, {start: {line: 4, ch: 5}, end: {line: 4, ch: 6}, primary: false, reversed: true}]); }); it("should properly coalesce selections that end/start on the same line when moving up", function () { myEditor.setSelections([{start: {line: 1, ch: 4}, end: {line: 2, ch: 4}}, {start: {line: 2, ch: 6}, end: {line: 2, ch: 6}}]); CommandManager.execute(Commands.EDIT_LINE_UP, myEditor); var lines = defaultContent.split("\n"); swapLines(lines, [[0, 1, 2]]); expect(myDocument.getText()).toEqual(lines.join("\n")); expectSelections([{start: {line: 0, ch: 4}, end: {line: 1, ch: 4}, primary: false, reversed: false}, {start: {line: 1, ch: 6}, end: {line: 1, ch: 6}, primary: true, reversed: false}]); }); it("should properly coalesce selections that end/start on the same line when moving down", function () { myEditor.setSelections([{start: {line: 1, ch: 4}, end: {line: 2, ch: 4}}, {start: {line: 2, ch: 6}, end: {line: 2, ch: 6}}]); CommandManager.execute(Commands.EDIT_LINE_DOWN, myEditor); var lines = defaultContent.split("\n"); swapLines(lines, [[3, 2, 1]]); expect(myDocument.getText()).toEqual(lines.join("\n")); expectSelections([{start: {line: 2, ch: 4}, end: {line: 3, ch: 4}, primary: false, reversed: false}, {start: {line: 3, ch: 6}, end: {line: 3, ch: 6}, primary: true, reversed: false}]); }); }); }); describe("Delete Line", function () { beforeEach(setupFullEditor); it("should delete the first line when selection is an IP in that line", function () { myEditor.setSelection({line: 0, ch: 5}, {line: 0, ch: 5}); CommandManager.execute(Commands.EDIT_DELETE_LINES, myEditor); var expectedText = defaultContent.split("\n").slice(1).join("\n"); expect(myDocument.getText()).toEqual(expectedText); }); it("should delete the first line when selection is a range in that line", function () { myEditor.setSelection({line: 0, ch: 5}, {line: 0, ch: 8}); CommandManager.execute(Commands.EDIT_DELETE_LINES, myEditor); var expectedText = defaultContent.split("\n").slice(1).join("\n"); expect(myDocument.getText()).toEqual(expectedText); }); it("should delete a middle line when selection is an IP in that line", function () { myEditor.setSelection({line: 2, ch: 5}, {line: 2, ch: 5}); CommandManager.execute(Commands.EDIT_DELETE_LINES, myEditor); var lines = defaultContent.split("\n"); lines.splice(2, 1); expect(myDocument.getText()).toEqual(lines.join("\n")); }); it("should delete a middle line when selection is a range in that line", function () { myEditor.setSelection({line: 2, ch: 5}, {line: 2, ch: 8}); CommandManager.execute(Commands.EDIT_DELETE_LINES, myEditor); var lines = defaultContent.split("\n"); lines.splice(2, 1); expect(myDocument.getText()).toEqual(lines.join("\n")); }); it("should delete the last line when selection is an IP in that line", function () { myEditor.setSelection({line: 7, ch: 0}, {line: 7, ch: 0}); CommandManager.execute(Commands.EDIT_DELETE_LINES, myEditor); var expectedText = defaultContent.split("\n").slice(0, 7).join("\n"); expect(myDocument.getText()).toEqual(expectedText); }); it("should delete the last line when selection is a range in that line", function () { myEditor.setSelection({line: 7, ch: 0}, {line: 7, ch: 1}); CommandManager.execute(Commands.EDIT_DELETE_LINES, myEditor); var expectedText = defaultContent.split("\n").slice(0, 7).join("\n"); expect(myDocument.getText()).toEqual(expectedText); }); it("should delete multiple lines starting at the top when selection spans them", function () { myEditor.setSelection({line: 0, ch: 5}, {line: 2, ch: 4}); CommandManager.execute(Commands.EDIT_DELETE_LINES, myEditor); var expectedText = defaultContent.split("\n").slice(3).join("\n"); expect(myDocument.getText()).toEqual(expectedText); }); it("should not delete an extra line after a whole selected line", function () { myEditor.setSelection({line: 1, ch: 0}, {line: 2, ch: 0}); CommandManager.execute(Commands.EDIT_DELETE_LINES, myEditor); var expectedText = defaultContent.split("\n"); expectedText.splice(1, 1); expect(myDocument.getText()).toEqual(expectedText.join("\n")); }); it("should not delete an extra line at the end of the document after a whole selected line", function () { myEditor.setSelection({line: 5, ch: 5}, {line: 7, ch: 0}); CommandManager.execute(Commands.EDIT_DELETE_LINES, myEditor); var expectedText = defaultContent.split("\n"); expectedText.splice(5, 2); expect(myDocument.getText()).toEqual(expectedText.join("\n")); }); it("should not delete an extra line after several whole lines that are selected", function () { myEditor.setSelection({line: 0, ch: 0}, {line: 3, ch: 0}); CommandManager.execute(Commands.EDIT_DELETE_LINES, myEditor); var expectedText = defaultContent.split("\n").slice(3).join("\n"); expect(myDocument.getText()).toEqual(expectedText); }); it("should delete multiple lines ending at the bottom when selection spans them", function () { myEditor.setSelection({line: 5, ch: 5}, {line: 7, ch: 1}); CommandManager.execute(Commands.EDIT_DELETE_LINES, myEditor); var expectedText = defaultContent.split("\n").slice(0, 5).join("\n"); expect(myDocument.getText()).toEqual(expectedText); }); it("should leave empty text when all lines are selected", function () { myEditor.setSelection({line: 0, ch: 4}, {line: 7, ch: 1}); CommandManager.execute(Commands.EDIT_DELETE_LINES, myEditor); expect(myDocument.getText()).toEqual(""); }); describe("with multiple selections", function () { it("should delete lines containing any cursor in a multiple selection", function () { myEditor.setSelections([{start: {line: 0, ch: 5}, end: {line: 0, ch: 5}}, {start: {line: 2, ch: 5}, end: {line: 2, ch: 5}}, {start: {line: 6, ch: 0}, end: {line: 6, ch: 0}}]); CommandManager.execute(Commands.EDIT_DELETE_LINES, myEditor); expect(myDocument.getText()).toEqual(contentWithDeletedLines([0, 2, 6])); expectSelections([ {start: {line: 0, ch: 0}, end: {line: 0, ch: 0}, primary: false, reversed: false}, {start: {line: 1, ch: 0}, end: {line: 1, ch: 0}, primary: false, reversed: false}, {start: {line: 4, ch: 0}, end: {line: 4, ch: 0}, primary: true, reversed: false} ]); }); it("should delete lines containing any range in a multiple selection", function () { myEditor.setSelections([{start: {line: 0, ch: 3}, end: {line: 0, ch: 5}}, {start: {line: 2, ch: 2}, end: {line: 2, ch: 5}}, {start: {line: 6, ch: 0}, end: {line: 6, ch: 1}}]); CommandManager.execute(Commands.EDIT_DELETE_LINES, myEditor); expect(myDocument.getText()).toEqual(contentWithDeletedLines([0, 2, 6])); expectSelections([ {start: {line: 0, ch: 0}, end: {line: 0, ch: 0}, primary: false, reversed: false}, {start: {line: 1, ch: 0}, end: {line: 1, ch: 0}, primary: false, reversed: false}, {start: {line: 4, ch: 0}, end: {line: 4, ch: 0}, primary: true, reversed: false} ]); }); it("should handle multiple cursors/selections on the same line (only deleting the line once)", function () { myEditor.setSelections([{start: {line: 0, ch: 5}, end: {line: 0, ch: 5}}, {start: {line: 2, ch: 3}, end: {line: 2, ch: 5}}, {start: {line: 2, ch: 7}, end: {line: 2, ch: 7}}, {start: {line: 6, ch: 0}, end: {line: 6, ch: 0}}]); CommandManager.execute(Commands.EDIT_DELETE_LINES, myEditor); expect(myDocument.getText()).toEqual(contentWithDeletedLines([0, 2, 6])); expectSelections([ {start: {line: 0, ch: 0}, end: {line: 0, ch: 0}, primary: false, reversed: false}, {start: {line: 1, ch: 0}, end: {line: 1, ch: 0}, primary: false, reversed: false}, {start: {line: 4, ch: 0}, end: {line: 4, ch: 0}, primary: true, reversed: false} ]); }); it("should handle multiple selections that span multiple lines", function () { myEditor.setSelections([{start: {line: 0, ch: 5}, end: {line: 1, ch: 5}}, {start: {line: 3, ch: 4}, end: {line: 4, ch: 5}}]); CommandManager.execute(Commands.EDIT_DELETE_LINES, myEditor); expect(myDocument.getText()).toEqual(contentWithDeletedLines([0, 1, 3, 4])); expectSelections([ {start: {line: 0, ch: 0}, end: {line: 0, ch: 0}, primary: false, reversed: false}, {start: {line: 1, ch: 0}, end: {line: 1, ch: 0}, primary: true, reversed: false} ]); }); it("should delete the rest of a selection that starts on a line previously deleted", function () { myEditor.setSelections([{start: {line: 0, ch: 5}, end: {line: 1, ch: 3}}, {start: {line: 1, ch: 5}, end: {line: 3, ch: 5}}]); CommandManager.execute(Commands.EDIT_DELETE_LINES, myEditor); expect(myDocument.getText()).toEqual(contentWithDeletedLines([0, 1, 2, 3])); expectSelections([ {start: {line: 0, ch: 0}, end: {line: 0, ch: 0}, primary: true, reversed: false} ]); }); it("should merge the primary selection into another selection on the same line", function () { myEditor.setSelections([{start: {line: 0, ch: 5}, end: {line: 0, ch: 5}}, {start: {line: 2, ch: 5}, end: {line: 2, ch: 5}}, {start: {line: 2, ch: 7}, end: {line: 2, ch: 7}, primary: true}, {start: {line: 6, ch: 0}, end: {line: 6, ch: 0}}]); CommandManager.execute(Commands.EDIT_DELETE_LINES, myEditor); expect(myDocument.getText()).toEqual(contentWithDeletedLines([0, 2, 6])); expectSelections([ {start: {line: 0, ch: 0}, end: {line: 0, ch: 0}, primary: false, reversed: false}, {start: {line: 1, ch: 0}, end: {line: 1, ch: 0}, primary: true, reversed: false}, {start: {line: 4, ch: 0}, end: {line: 4, ch: 0}, primary: false, reversed: false} ]); }); }); }); describe("Delete Line - editor with visible range", function () { it("should delete the top line of the visible range", function () { makeEditorWithRange({startLine: 1, endLine: 5}); myEditor.setSelection({line: 1, ch: 5}, {line: 1, ch: 5}); CommandManager.execute(Commands.EDIT_DELETE_LINES, myEditor); var lines = defaultContent.split("\n"); lines.splice(1, 1); expect(myDocument.getText()).toEqual(lines.join("\n")); expect(myEditor._visibleRange.startLine).toNotBe(null); expect(myEditor._visibleRange.endLine).toNotBe(null); }); it("should delete the bottom line of the visible range", function () { makeEditorWithRange({startLine: 1, endLine: 5}); myEditor.setSelection({line: 5, ch: 2}, {line: 5, ch: 2}); CommandManager.execute(Commands.EDIT_DELETE_LINES, myEditor); var lines = defaultContent.split("\n"); lines.splice(5, 1); expect(myDocument.getText()).toEqual(lines.join("\n")); expect(myEditor._visibleRange.startLine).toNotBe(null); expect(myEditor._visibleRange.endLine).toNotBe(null); }); it("should leave a single newline when all visible lines are selected", function () { makeEditorWithRange({startLine: 1, endLine: 5}); myEditor.setSelection({line: 1, ch: 5}, {line: 5, ch: 2}); CommandManager.execute(Commands.EDIT_DELETE_LINES, myEditor); var lines = defaultContent.split("\n"); lines.splice(1, 5, ""); expect(myDocument.getText()).toEqual(lines.join("\n")); expect(myEditor._visibleRange.startLine).toNotBe(null); expect(myEditor._visibleRange.endLine).toNotBe(null); }); it("should leave a single newline when only one line is visible", function () { makeEditorWithRange({startLine: 3, endLine: 3}); myEditor.setSelection({line: 3, ch: 4}, {line: 3, ch: 4}); CommandManager.execute(Commands.EDIT_DELETE_LINES, myEditor); var lines = defaultContent.split("\n"); lines.splice(3, 1, ""); expect(myDocument.getText()).toEqual(lines.join("\n")); expect(myEditor._visibleRange.startLine).toNotBe(null); expect(myEditor._visibleRange.endLine).toNotBe(null); }); it("should properly handle multiple selection, including first and last line deletion", function () { makeEditorWithRange({startLine: 1, endLine: 6}); myEditor.setSelections([{start: {line: 1, ch: 5}, end: {line: 1, ch: 5}}, {start: {line: 3, ch: 5}, end: {line: 3, ch: 5}}, {start: {line: 6, ch: 0}, end: {line: 6, ch: 0}}]); CommandManager.execute(Commands.EDIT_DELETE_LINES, myEditor); expect(myDocument.getText()).toEqual(contentWithDeletedLines([1, 3, 6])); expectSelections([ {start: {line: 1, ch: 0}, end: {line: 1, ch: 0}, primary: false, reversed: false}, {start: {line: 2, ch: 0}, end: {line: 2, ch: 0}, primary: false, reversed: false}, {start: {line: 3, ch: 5}, end: {line: 3, ch: 5}, primary: true, reversed: false} ]); }); }); describe("Select Line", function () { // Note that these indirectly test Editor.expandSelectionsToLines() as well. beforeEach(setupFullEditor); it("should select the first line with IP in that line", function () { myEditor.setSelection({line: 0, ch: 5}, {line: 0, ch: 5}); CommandManager.execute(Commands.EDIT_SELECT_LINE, myEditor); expectSelection({start: {line: 0, ch: 0}, end: {line: 1, ch: 0}}); }); it("should select the last line with IP in that line", function () { myEditor.setSelection({line: 7, ch: 0}, {line: 7, ch: 0}); CommandManager.execute(Commands.EDIT_SELECT_LINE, myEditor); expectSelection({start: {line: 7, ch: 0}, end: {line: 7, ch: 1}}); }); it("should select all in one-line file", function () { myDocument.setText("// x"); myEditor.setSelection({line: 0, ch: 0}, {line: 0, ch: 0}); CommandManager.execute(Commands.EDIT_SELECT_LINE, myEditor); expectSelection({start: {line: 0, ch: 0}, end: {line: 0, ch: 4}}); }); it("should extend selection to whole line", function () { myEditor.setSelection({line: 1, ch: 4}, {line: 1, ch: 8}); CommandManager.execute(Commands.EDIT_SELECT_LINE, myEditor); expectSelection({start: {line: 1, ch: 0}, end: {line: 2, ch: 0}}); }); it("should extend whole line selection to next line", function () { myEditor.setSelection({line: 1, ch: 0}, {line: 2, ch: 0}); CommandManager.execute(Commands.EDIT_SELECT_LINE, myEditor); expectSelection({start: {line: 1, ch: 0}, end: {line: 3, ch: 0}}); }); it("should extend multi-line selection to full lines", function () { myEditor.setSelection({line: 1, ch: 4}, {line: 3, ch: 9}); CommandManager.execute(Commands.EDIT_SELECT_LINE, myEditor); expectSelection({start: {line: 1, ch: 0}, end: {line: 4, ch: 0}}); }); it("should extend full multi-line selection to one more line", function () { myEditor.setSelection({line: 1, ch: 0}, {line: 4, ch: 0}); CommandManager.execute(Commands.EDIT_SELECT_LINE, myEditor); expectSelection({start: {line: 1, ch: 0}, end: {line: 5, ch: 0}}); }); describe("with multiple selections", function () { it("should extend multiple cursors to multiple lines", function () { myEditor.setSelections([{start: {line: 0, ch: 5}, end: {line: 0, ch: 5}}, {start: {line: 3, ch: 9}, end: {line: 3, ch: 9}}, {start: {line: 7, ch: 0}, end: {line: 7, ch: 0}}]); CommandManager.execute(Commands.EDIT_SELECT_LINE, myEditor); expectSelections([{start: {line: 0, ch: 0}, end: {line: 1, ch: 0}, reversed: false, primary: false}, {start: {line: 3, ch: 0}, end: {line: 4, ch: 0}, reversed: false, primary: false}, {start: {line: 7, ch: 0}, end: {line: 7, ch: 1}, reversed: false, primary: true}]); }); it("should extend multiple selections to multiple lines", function () { myEditor.setSelections([{start: {line: 0, ch: 0}, end: {line: 0, ch: 5}}, {start: {line: 3, ch: 0}, end: {line: 3, ch: 9}}, {start: {line: 7, ch: 0}, end: {line: 7, ch: 1}}]); CommandManager.execute(Commands.EDIT_SELECT_LINE, myEditor); expectSelections([{start: {line: 0, ch: 0}, end: {line: 1, ch: 0}, reversed: false, primary: false}, {start: {line: 3, ch: 0}, end: {line: 4, ch: 0}, reversed: false, primary: false}, {start: {line: 7, ch: 0}, end: {line: 7, ch: 1}, reversed: false, primary: true}]); }); it("should extend multiple multi-line selections to whole lines, and handle end properly", function () { myEditor.setSelections([{start: {line: 0, ch: 2}, end: {line: 1, ch: 3}}, {start: {line: 3, ch: 2}, end: {line: 4, ch: 3}}, {start: {line: 6, ch: 2}, end: {line: 7, ch: 0}}]); CommandManager.execute(Commands.EDIT_SELECT_LINE, myEditor); expectSelections([{start: {line: 0, ch: 0}, end: {line: 2, ch: 0}, reversed: false, primary: false}, {start: {line: 3, ch: 0}, end: {line: 5, ch: 0}, reversed: false, primary: false}, {start: {line: 6, ch: 0}, end: {line: 7, ch: 1}, reversed: false, primary: true}]); }); it("should extend whole lines in multiple selection to next line, except at end", function () { myEditor.setSelections([{start: {line: 0, ch: 0}, end: {line: 1, ch: 0}}, {start: {line: 3, ch: 0}, end: {line: 4, ch: 0}}, {start: {line: 7, ch: 0}, end: {line: 7, ch: 1}}]); CommandManager.execute(Commands.EDIT_SELECT_LINE, myEditor); expectSelections([{start: {line: 0, ch: 0}, end: {line: 2, ch: 0}, reversed: false, primary: false}, {start: {line: 3, ch: 0}, end: {line: 5, ch: 0}, reversed: false, primary: false}, {start: {line: 7, ch: 0}, end: {line: 7, ch: 1}, reversed: false, primary: true}]); }); it("should extend multiple lines in multiple selection to additional line, and handle end properly", function () { myEditor.setSelections([{start: {line: 0, ch: 0}, end: {line: 2, ch: 0}}, {start: {line: 4, ch: 0}, end: {line: 7, ch: 0}}]); CommandManager.execute(Commands.EDIT_SELECT_LINE, myEditor); expectSelections([{start: {line: 0, ch: 0}, end: {line: 3, ch: 0}, reversed: false, primary: false}, {start: {line: 4, ch: 0}, end: {line: 7, ch: 1}, reversed: false, primary: true}]); }); it("should merge selections that collide", function () { myEditor.setSelections([{start: {line: 1, ch: 3}, end: {line: 1, ch: 3}}, {start: {line: 2, ch: 4}, end: {line: 2, ch: 4}}]); CommandManager.execute(Commands.EDIT_SELECT_LINE, myEditor); expectSelections([{start: {line: 1, ch: 0}, end: {line: 3, ch: 0}, reversed: false, primary: true}]); }); it("should track a non-default primary selection", function () { myEditor.setSelections([{start: {line: 0, ch: 0}, end: {line: 1, ch: 0}}, {start: {line: 3, ch: 0}, end: {line: 4, ch: 0}, primary: true}, {start: {line: 7, ch: 0}, end: {line: 7, ch: 1}}]); CommandManager.execute(Commands.EDIT_SELECT_LINE, myEditor); expectSelection({start: {line: 3, ch: 0}, end: {line: 5, ch: 0}}); }); it("should track a reversed selection", function () { myEditor.setSelections([{start: {line: 0, ch: 0}, end: {line: 1, ch: 0}}, {start: {line: 3, ch: 0}, end: {line: 4, ch: 0}, reversed: true}, {start: {line: 7, ch: 0}, end: {line: 7, ch: 1}}]); CommandManager.execute(Commands.EDIT_SELECT_LINE, myEditor); expectSelections([{start: {line: 0, ch: 0}, end: {line: 2, ch: 0}, reversed: false, primary: false}, {start: {line: 3, ch: 0}, end: {line: 5, ch: 0}, reversed: true, primary: false}, {start: {line: 7, ch: 0}, end: {line: 7, ch: 1}, reversed: false, primary: true}]); }); }); }); describe("Select Line - editor with visible range", function () { it("shouldn't select past end of visible range, IP in middle of last visible line", function () { makeEditorWithRange({startLine: 1, endLine: 5}); myEditor.setSelection({line: 5, ch: 4}, {line: 5, ch: 4}); CommandManager.execute(Commands.EDIT_SELECT_LINE, myEditor); expectSelection({start: {line: 5, ch: 0}, end: {line: 5, ch: 5}}); }); it("shouldn't select past end of visible range, IP at start of last visible line", function () { makeEditorWithRange({startLine: 1, endLine: 5}); myEditor.setSelection({line: 5, ch: 0}, {line: 5, ch: 0}); CommandManager.execute(Commands.EDIT_SELECT_LINE, myEditor); expectSelection({start: {line: 5, ch: 0}, end: {line: 5, ch: 5}}); }); it("should extend selection to include last line of visible range", function () { makeEditorWithRange({startLine: 1, endLine: 5}); myEditor.setSelection({line: 4, ch: 4}, {line: 4, ch: 4}); CommandManager.execute(Commands.EDIT_SELECT_LINE, myEditor); expectSelection({start: {line: 4, ch: 0}, end: {line: 5, ch: 0}}); }); it("should properly expand multiselection at start and end", function () { makeEditorWithRange({startLine: 1, endLine: 5}); myEditor.setSelections([{start: {line: 1, ch: 5}, end: {line: 1, ch: 5}}, {start: {line: 5, ch: 0}, end: {line: 5, ch: 0}}]); CommandManager.execute(Commands.EDIT_SELECT_LINE, myEditor); expectSelections([{start: {line: 1, ch: 0}, end: {line: 2, ch: 0}, reversed: false, primary: false}, {start: {line: 5, ch: 0}, end: {line: 5, ch: 5}, reversed: false, primary: true}]); }); }); describe("Open Line Above and Below", function () { var indentUnit = SpecRunnerUtils.EDITOR_USE_TABS ? 1 : SpecRunnerUtils.EDITOR_SPACE_UNITS, indentation = (function () { // generate indent string once if (SpecRunnerUtils.EDITOR_USE_TABS) { return "\t"; } var spaces = []; spaces.length = indentUnit + 1; return spaces.join(" "); }()); beforeEach(setupFullEditor); it("should insert new line above if no selection", function () { // place cursor in line 1 myEditor.setCursorPos(1, 10); CommandManager.execute(Commands.EDIT_OPEN_LINE_ABOVE, myEditor); var lines = defaultContent.split("\n"); lines.splice(1, 0, indentation); var expectedText = lines.join("\n"); expect(myDocument.getText()).toEqual(expectedText); expectCursorAt({line: 1, ch: indentUnit}); }); it("should insert new line above the first line if no selection", function () { // place cursor in the first line myEditor.setCursorPos(0, 0); CommandManager.execute(Commands.EDIT_OPEN_LINE_ABOVE, myEditor); var lines = defaultContent.split("\n"); lines.splice(0, 0, ""); var expectedText = lines.join("\n"); expect(myDocument.getText()).toEqual(expectedText); expectCursorAt({line: 0, ch: 0}); }); it("should insert new line above the last line if no selection", function () { // place cursor in the last line myEditor.setCursorPos(7, 0); CommandManager.execute(Commands.EDIT_OPEN_LINE_ABOVE, myEditor); var lines = defaultContent.split("\n"); lines.splice(7, 0, indentation); var expectedText = lines.join("\n"); expect(myDocument.getText()).toEqual(expectedText); expectCursorAt({line: 7, ch: indentUnit}); }); it("should insert new line above with no indentation if no selection", function () { // place cursor in the middle of line 0 myEditor.setCursorPos(0, 10); CommandManager.execute(Commands.EDIT_OPEN_LINE_ABOVE, myEditor); var lines = defaultContent.split("\n"); lines.splice(0, 0, ""); var expectedText = lines.join("\n"); expect(myDocument.getText()).toEqual(expectedText); expectCursorAt({line: 0, ch: 0}); }); it("should insert new line above when characters selected", function () { // select characters 0-10 in line 1 myEditor.setSelection({line: 1, ch: 0}, {line: 1, ch: 10}); CommandManager.execute(Commands.EDIT_OPEN_LINE_ABOVE, myEditor); var lines = defaultContent.split("\n"); lines.splice(1, 0, indentation); var expectedText = lines.join("\n"); expect(myDocument.getText()).toEqual(expectedText); expectCursorAt({line: 1, ch: indentUnit}); }); it("should insert new line above when linewise selection", function () { // select all of line 1 and 2, Including trailing \n myEditor.setSelection({line: 1, ch: 0}, {line: 3, ch: 0}); CommandManager.execute(Commands.EDIT_OPEN_LINE_ABOVE, myEditor); var lines = defaultContent.split("\n"); lines.splice(1, 0, indentation); var expectedText = lines.join("\n"); expect(myDocument.getText()).toEqual(expectedText); expectCursorAt({line: 1, ch: indentUnit}); }); it("should insert new line above when multiple line selection", function () { // selection from line 2 character 6 to line 5 character 2 myEditor.setSelection({line: 2, ch: 6}, {line: 5, ch: 2}); CommandManager.execute(Commands.EDIT_OPEN_LINE_ABOVE, myEditor); var lines = defaultContent.split("\n"); lines.splice(2, 0, indentation + indentation); var expectedText = lines.join("\n"); expect(myDocument.getText()).toEqual(expectedText); expectCursorAt({line: 2, ch: indentUnit * 2}); }); it("should insert new line below when no selection", function () { // place cursor in line 0 myEditor.setCursorPos(0, 10); CommandManager.execute(Commands.EDIT_OPEN_LINE_BELOW, myEditor); var lines = defaultContent.split("\n"); lines.splice(1, 0, indentation); var expectedText = lines.join("\n"); expect(myDocument.getText()).toEqual(expectedText); expectCursorAt({line: 1, ch: indentUnit}); }); it("should insert new line below the first line if no selection", function () { // place cursor in the first line myEditor.setCursorPos(0, 0); CommandManager.execute(Commands.EDIT_OPEN_LINE_BELOW, myEditor); var lines = defaultContent.split("\n"); lines.splice(1, 0, indentation); var expectedText = lines.join("\n"); expect(myDocument.getText()).toEqual(expectedText); expectCursorAt({line: 1, ch: indentUnit}); }); it("should insert new line below the last line if no selection", function () { // place cursor in the last line myEditor.setCursorPos(7, 0); CommandManager.execute(Commands.EDIT_OPEN_LINE_BELOW, myEditor); var lines = defaultContent.split("\n"); lines.splice(8, 0, ""); var expectedText = lines.join("\n"); expect(myDocument.getText()).toEqual(expectedText); expectCursorAt({line: 8, ch: 0}); }); it("should insert new line below with no indentation if no selection", function () { // place cursor in line 7 character 1 myEditor.setCursorPos(7, 1); CommandManager.execute(Commands.EDIT_OPEN_LINE_BELOW, myEditor); var lines = defaultContent.split("\n"); lines.splice(8, 0, ""); var expectedText = lines.join("\n"); expect(myDocument.getText()).toEqual(expectedText); expectCursorAt({line: 8, ch: 0}); }); it("should insert new line below when characters selected", function () { // select characters 0-10 in line 0 myEditor.setSelection({line: 0, ch: 0}, {line: 0, ch: 10}); CommandManager.execute(Commands.EDIT_OPEN_LINE_BELOW, myEditor); var lines = defaultContent.split("\n"); lines.splice(1, 0, indentation); var expectedText = lines.join("\n"); expect(myDocument.getText()).toEqual(expectedText); expectCursorAt({line: 1, ch: indentUnit}); }); it("should insert new line below when linewise selection", function () { // select all of line 1 and 2, Including trailing \n myEditor.setSelection({line: 1, ch: 0}, {line: 3, ch: 0}); CommandManager.execute(Commands.EDIT_OPEN_LINE_BELOW, myEditor); var lines = defaultContent.split("\n"); lines.splice(3, 0, indentation + indentation); var expectedText = lines.join("\n"); expect(myDocument.getText()).toEqual(expectedText); expectCursorAt({line: 3, ch: indentUnit * 2}); }); it("should insert new line below when multiple line selection", function () { // selection from line 1 character 4 to line 4 character 2 myEditor.setSelection({line: 1, ch: 4}, {line: 4, ch: 2}); CommandManager.execute(Commands.EDIT_OPEN_LINE_BELOW, myEditor); var lines = defaultContent.split("\n"); lines.splice(5, 0, indentation + indentation); var expectedText = lines.join("\n"); expect(myDocument.getText()).toEqual(expectedText); expectCursorAt({line: 5, ch: indentUnit * 2}); }); describe("with multiple selections", function () { it("should insert new line above each selection cursor/range", function () { myEditor.setSelections([{start: {line: 1, ch: 1}, end: {line: 1, ch: 1}}, {start: {line: 2, ch: 4}, end: {line: 2, ch: 6}}, {start: {line: 4, ch: 5}, end: {line: 5, ch: 8}}]); CommandManager.execute(Commands.EDIT_OPEN_LINE_ABOVE, myEditor); var lines = defaultContent.split("\n"); lines.splice(4, 0, indentation + indentation); lines.splice(2, 0, indentation + indentation); lines.splice(1, 0, indentation); expect(myDocument.getText()).toEqual(lines.join("\n")); expectSelections([{start: {line: 1, ch: 4}, end: {line: 1, ch: 4}, primary: false, reversed: false}, {start: {line: 3, ch: 8}, end: {line: 3, ch: 8}, primary: false, reversed: false}, {start: {line: 6, ch: 8}, end: {line: 6, ch: 8}, primary: true, reversed: false}]); }); it("should ignore multiple selections on same line when inserting above", function () { myEditor.setSelections([{start: {line: 1, ch: 1}, end: {line: 1, ch: 1}}, {start: {line: 2, ch: 4}, end: {line: 2, ch: 6}}, {start: {line: 2, ch: 7}, end: {line: 2, ch: 7}}, {start: {line: 4, ch: 5}, end: {line: 5, ch: 8}}]); CommandManager.execute(Commands.EDIT_OPEN_LINE_ABOVE, myEditor); var lines = defaultContent.split("\n"); lines.splice(4, 0, indentation + indentation); lines.splice(2, 0, indentation + indentation); lines.splice(1, 0, indentation); expect(myDocument.getText()).toEqual(lines.join("\n")); expectSelections([{start: {line: 1, ch: 4}, end: {line: 1, ch: 4}, primary: false, reversed: false}, {start: {line: 3, ch: 8}, end: {line: 3, ch: 8}, primary: false, reversed: false}, {start: {line: 6, ch: 8}, end: {line: 6, ch: 8}, primary: true, reversed: false}]); }); it("should not ignore multiple selections that end on the same line if the second one starts on a different line when inserting above", function () { myEditor.setSelections([{start: {line: 1, ch: 1}, end: {line: 1, ch: 1}}, {start: {line: 2, ch: 4}, end: {line: 4, ch: 2}}, {start: {line: 4, ch: 6}, end: {line: 4, ch: 6}}, {start: {line: 5, ch: 5}, end: {line: 5, ch: 8}}]); CommandManager.execute(Commands.EDIT_OPEN_LINE_ABOVE, myEditor); var lines = defaultContent.split("\n"); lines.splice(5, 0, indentation + indentation); lines.splice(4, 0, indentation + indentation); lines.splice(2, 0, indentation + indentation); lines.splice(1, 0, indentation); expect(myDocument.getText()).toEqual(lines.join("\n")); expectSelections([{start: {line: 1, ch: 4}, end: {line: 1, ch: 4}, primary: false, reversed: false}, {start: {line: 3, ch: 8}, end: {line: 3, ch: 8}, primary: false, reversed: false}, {start: {line: 6, ch: 8}, end: {line: 6, ch: 8}, primary: false, reversed: false}, {start: {line: 8, ch: 8}, end: {line: 8, ch: 8}, primary: true, reversed: false}]); }); it("should insert new line below each selection cursor/range", function () { myEditor.setSelections([{start: {line: 1, ch: 1}, end: {line: 1, ch: 1}}, {start: {line: 2, ch: 4}, end: {line: 2, ch: 6}}, {start: {line: 4, ch: 5}, end: {line: 5, ch: 8}}]); CommandManager.execute(Commands.EDIT_OPEN_LINE_BELOW, myEditor); var lines = defaultContent.split("\n"); lines.splice(6, 0, indentation); lines.splice(3, 0, indentation + indentation); lines.splice(2, 0, indentation + indentation); expect(myDocument.getText()).toEqual(lines.join("\n")); expectSelections([{start: {line: 2, ch: 8}, end: {line: 2, ch: 8}, primary: false, reversed: false}, {start: {line: 4, ch: 8}, end: {line: 4, ch: 8}, primary: false, reversed: false}, {start: {line: 8, ch: 4}, end: {line: 8, ch: 4}, primary: true, reversed: false}]); }); it("should ignore multiple selections on same line when inserting below", function () { myEditor.setSelections([{start: {line: 1, ch: 1}, end: {line: 1, ch: 1}}, {start: {line: 2, ch: 4}, end: {line: 2, ch: 6}}, {start: {line: 2, ch: 7}, end: {line: 2, ch: 7}}, {start: {line: 4, ch: 5}, end: {line: 5, ch: 8}}]); CommandManager.execute(Commands.EDIT_OPEN_LINE_BELOW, myEditor); var lines = defaultContent.split("\n"); lines.splice(6, 0, indentation); lines.splice(3, 0, indentation + indentation); lines.splice(2, 0, indentation + indentation); expect(myDocument.getText()).toEqual(lines.join("\n")); expectSelections([{start: {line: 2, ch: 8}, end: {line: 2, ch: 8}, primary: false, reversed: false}, {start: {line: 4, ch: 8}, end: {line: 4, ch: 8}, primary: false, reversed: false}, {start: {line: 8, ch: 4}, end: {line: 8, ch: 4}, primary: true, reversed: false}]); }); it("should not ignore multiple selections that start on the same line if the second one ends on a different line when inserting below", function () { myEditor.setSelections([{start: {line: 1, ch: 1}, end: {line: 1, ch: 1}}, {start: {line: 2, ch: 4}, end: {line: 2, ch: 6}}, {start: {line: 4, ch: 2}, end: {line: 4, ch: 2}}, {start: {line: 4, ch: 5}, end: {line: 5, ch: 8}}]); CommandManager.execute(Commands.EDIT_OPEN_LINE_BELOW, myEditor); var lines = defaultContent.split("\n"); lines.splice(6, 0, indentation); lines.splice(5, 0, indentation + indentation); lines.splice(3, 0, indentation + indentation); lines.splice(2, 0, indentation + indentation); expect(myDocument.getText()).toEqual(lines.join("\n")); expectSelections([{start: {line: 2, ch: 8}, end: {line: 2, ch: 8}, primary: false, reversed: false}, {start: {line: 4, ch: 8}, end: {line: 4, ch: 8}, primary: false, reversed: false}, {start: {line: 7, ch: 8}, end: {line: 7, ch: 8}, primary: false, reversed: false}, {start: {line: 9, ch: 4}, end: {line: 9, ch: 4}, primary: true, reversed: false}]); }); }); }); describe("Add Line to Selection", function () { beforeEach(setupFullEditor); it("should add a cursor on the next line after a single cursor selection and make it primary", function () { myEditor.setSelection({line: 1, ch: 5}, {line: 1, ch: 5}); CommandManager.execute(Commands.EDIT_ADD_CUR_TO_NEXT_LINE, myEditor); expectSelections([{start: {line: 1, ch: 5}, end: {line: 1, ch: 5}, primary: false, reversed: false}, {start: {line: 2, ch: 5}, end: {line: 2, ch: 5}, primary: true, reversed: false}]); }); it("should add a cursor on the previous line before a single cursor selection and make it primary", function () { myEditor.setSelection({line: 1, ch: 5}, {line: 1, ch: 5}); CommandManager.execute(Commands.EDIT_ADD_CUR_TO_PREV_LINE, myEditor); expectSelections([{start: {line: 0, ch: 5}, end: {line: 0, ch: 5}, primary: true, reversed: false}, {start: {line: 1, ch: 5}, end: {line: 1, ch: 5}, primary: false, reversed: false}]); }); it("should add a cursor on the next line after a single-line range selection, below the end pos of the range", function () { myEditor.setSelection({line: 1, ch: 5}, {line: 1, ch: 8}); CommandManager.execute(Commands.EDIT_ADD_CUR_TO_NEXT_LINE, myEditor); expectSelections([{start: {line: 1, ch: 5}, end: {line: 1, ch: 8}, primary: false, reversed: false}, {start: {line: 2, ch: 8}, end: {line: 2, ch: 8}, primary: true, reversed: false}]); }); it("should add a cursor on the previous line after a single-line range selection, above the start pos of the range", function () { myEditor.setSelection({line: 1, ch: 5}, {line: 1, ch: 8}); CommandManager.execute(Commands.EDIT_ADD_CUR_TO_PREV_LINE, myEditor); expectSelections([{start: {line: 0, ch: 5}, end: {line: 0, ch: 5}, primary: true, reversed: false}, {start: {line: 1, ch: 5}, end: {line: 1, ch: 8}, primary: false, reversed: false}]); }); it("should add a cursor on the next line after a multi-line range selection, below the end pos of the range", function () { myEditor.setSelection({line: 1, ch: 5}, {line: 2, ch: 8}); CommandManager.execute(Commands.EDIT_ADD_CUR_TO_NEXT_LINE, myEditor); expectSelections([{start: {line: 1, ch: 5}, end: {line: 2, ch: 8}, primary: false, reversed: false}, {start: {line: 3, ch: 8}, end: {line: 3, ch: 8}, primary: true, reversed: false}]); }); it("should add a cursor on the previous line before a multi-line range selection, above the start pos of the range", function () { myEditor.setSelection({line: 1, ch: 5}, {line: 2, ch: 8}); CommandManager.execute(Commands.EDIT_ADD_CUR_TO_PREV_LINE, myEditor); expectSelections([{start: {line: 0, ch: 5}, end: {line: 0, ch: 5}, primary: true, reversed: false}, {start: {line: 1, ch: 5}, end: {line: 2, ch: 8}, primary: false, reversed: false}]); }); it("should do nothing if trying to add selection down at last line", function () { myEditor.setSelection({line: 7, ch: 0}, {line: 7, ch: 0}); CommandManager.execute(Commands.EDIT_ADD_CUR_TO_NEXT_LINE, myEditor); expectSelections([{start: {line: 7, ch: 0}, end: {line: 7, ch: 0}, primary: true, reversed: false}]); }); it("should do nothing if trying to add selection up at first line", function () { myEditor.setSelection({line: 0, ch: 5}, {line: 0, ch: 5}); CommandManager.execute(Commands.EDIT_ADD_CUR_TO_PREV_LINE, myEditor); expectSelections([{start: {line: 0, ch: 5}, end: {line: 0, ch: 5}, primary: true, reversed: false}]); }); it("should add cursors below each range in a multiple selection, making the correct one primary", function () { myEditor.setSelections([{start: {line: 1, ch: 5}, end: {line: 1, ch: 5}}, {start: {line: 3, ch: 2}, end: {line: 3, ch: 8}}]); CommandManager.execute(Commands.EDIT_ADD_CUR_TO_NEXT_LINE, myEditor); expectSelections([{start: {line: 1, ch: 5}, end: {line: 1, ch: 5}, primary: false, reversed: false}, {start: {line: 2, ch: 5}, end: {line: 2, ch: 5}, primary: false, reversed: false}, {start: {line: 3, ch: 2}, end: {line: 3, ch: 8}, primary: false, reversed: false}, {start: {line: 4, ch: 8}, end: {line: 4, ch: 8}, primary: true, reversed: false}]); }); it("should add cursors above each range in a multiple selection, making the correct one primary", function () { myEditor.setSelections([{start: {line: 1, ch: 5}, end: {line: 1, ch: 5}}, {start: {line: 3, ch: 2}, end: {line: 3, ch: 8}}]); CommandManager.execute(Commands.EDIT_ADD_CUR_TO_PREV_LINE, myEditor); expectSelections([{start: {line: 0, ch: 5}, end: {line: 0, ch: 5}, primary: false, reversed: false}, {start: {line: 1, ch: 5}, end: {line: 1, ch: 5}, primary: false, reversed: false}, {start: {line: 2, ch: 2}, end: {line: 2, ch: 2}, primary: true, reversed: false}, {start: {line: 3, ch: 2}, end: {line: 3, ch: 8}, primary: false, reversed: false}]); }); it("should not add cursors downward that overlap another selection", function () { myEditor.setSelections([{start: {line: 1, ch: 5}, end: {line: 1, ch: 5}}, {start: {line: 2, ch: 2}, end: {line: 2, ch: 8}}]); CommandManager.execute(Commands.EDIT_ADD_CUR_TO_NEXT_LINE, myEditor); expectSelections([{start: {line: 1, ch: 5}, end: {line: 1, ch: 5}, primary: false, reversed: false}, {start: {line: 2, ch: 2}, end: {line: 2, ch: 8}, primary: false, reversed: false}, {start: {line: 3, ch: 8}, end: {line: 3, ch: 8}, primary: true, reversed: false}]); }); it("should not add cursors upward that overlap another selection", function () { myEditor.setSelections([{start: {line: 1, ch: 2}, end: {line: 1, ch: 8}}, {start: {line: 2, ch: 5}, end: {line: 2, ch: 5}}]); CommandManager.execute(Commands.EDIT_ADD_CUR_TO_PREV_LINE, myEditor); expectSelections([{start: {line: 0, ch: 2}, end: {line: 0, ch: 2}, primary: false, reversed: false}, {start: {line: 1, ch: 2}, end: {line: 1, ch: 8}, primary: true, reversed: false}, {start: {line: 2, ch: 5}, end: {line: 2, ch: 5}, primary: false, reversed: false}]); }); }); describe("Add Line to Selection with Tabs", function () { beforeEach(function () { setupFullEditor(tabbedContent); }); it("should add a cursor on the next line before a single cursor in same visual position", function () { myEditor.setSelection({line: 1, ch: 8}, {line: 1, ch: 8}); CommandManager.execute(Commands.EDIT_ADD_CUR_TO_NEXT_LINE, myEditor); expectSelections([{start: {line: 1, ch: 8}, end: {line: 1, ch: 8}, primary: false, reversed: false}, {start: {line: 2, ch: 12}, end: {line: 2, ch: 12}, primary: true, reversed: false}]); }); it("should add a cursor on the previous line before a single cursor selection in same visual position", function () { myEditor.setSelection({line: 2, ch: 12}, {line: 2, ch: 12}); CommandManager.execute(Commands.EDIT_ADD_CUR_TO_PREV_LINE, myEditor); expectSelections([{start: {line: 1, ch: 8}, end: {line: 1, ch: 8}, primary: true, reversed: false}, {start: {line: 2, ch: 12}, end: {line: 2, ch: 12}, primary: false, reversed: false}]); }); }); describe("EditorCommandHandlers Integration", function () { this.category = "integration"; beforeFirst(function () { createTestWindow(this); }); afterLast(function () { closeTestWindow(); }); describe("Move Lines Up/Down - inline editor", function () { var moveContent = ".testClass {\n" + " color: red;\n" + "}"; beforeEach(function () { openInlineEditor(this); }); afterEach(function () { closeFilesInTestWindow(); }); it("should not move the first line of the inline editor up", function () { myEditor.setCursorPos({line: 0, ch: 5}); CommandManager.execute(Commands.EDIT_LINE_UP, myEditor); expect(myEditor.document.getText()).toEqual(moveContent); expect(myEditor._codeMirror.doc.historySize().undo).toBe(0); expect(myEditor.getFirstVisibleLine()).toBe(0); expect(myEditor.getLastVisibleLine()).toBe(2); }); it("should not move the last line of the inline editor down", function () { myEditor.setCursorPos({line: 2, ch: 5}); CommandManager.execute(Commands.EDIT_LINE_DOWN, myEditor); expect(myEditor.document.getText()).toEqual(moveContent); expect(myEditor._codeMirror.doc.historySize().undo).toBe(0); expect(myEditor.getFirstVisibleLine()).toBe(0); expect(myEditor.getLastVisibleLine()).toBe(2); }); it("should be able to move the second to last line of the inline editor down", function () { myEditor.setCursorPos({line: 1, ch: 5}); CommandManager.execute(Commands.EDIT_LINE_DOWN, myEditor); var lines = moveContent.split("\n"); var temp = lines[1]; lines[1] = lines[2]; lines[2] = temp; var expectedText = lines.join("\n"); expect(myEditor.document.getText()).toEqual(expectedText); expect(myEditor.getFirstVisibleLine()).toBe(0); expect(myEditor.getLastVisibleLine()).toBe(2); }); it("should be able to move the last line of the inline editor up", function () { myEditor.setCursorPos({line: 2, ch: 0}); CommandManager.execute(Commands.EDIT_LINE_UP, myEditor); var lines = moveContent.split("\n"); var temp = lines[1]; lines[1] = lines[2]; lines[2] = temp; var expectedText = lines.join("\n"); expect(myEditor.document.getText()).toEqual(expectedText); expect(myEditor.getFirstVisibleLine()).toBe(0); expect(myEditor.getLastVisibleLine()).toBe(2); }); }); describe("Editor Navigation Commands", function () { it("should jump to definition", function () { var promise, selection; runs(function () { promise = CommandManager.execute(Commands.CMD_ADD_TO_WORKINGSET_AND_OPEN, {fullPath: testPath + "/test.js"}); waitsForDone(promise, "Open into working set"); }); runs(function () { myEditor = EditorManager.getCurrentFullEditor(); myEditor.setCursorPos({line: 5, ch: 8}); promise = CommandManager.execute(Commands.NAVIGATE_JUMPTO_DEFINITION); waitsForDone(promise, "Jump To Definition"); }); runs(function () { selection = myEditor.getSelection(); expect(fixSel(selection)).toEqual(fixSel({ start: {line: 0, ch: 9}, end: {line: 0, ch: 15} })); }); }); }); describe("Open Line Above and Below - inline editor", function () { var content = ".testClass {\n" + " color: red;\n" + "}"; beforeEach(function () { openInlineEditor(this); }); afterEach(function () { closeFilesInTestWindow(); }); it("should insert new line above the first line of the inline editor", function () { myEditor.setSelection({line: 0, ch: 4}, {line: 0, ch: 6}); CommandManager.execute(Commands.EDIT_OPEN_LINE_ABOVE, myEditor); var lines = content.split("\n"); lines.splice(0, 0, ""); var expectedText = lines.join("\n"); expect(myEditor.document.getText()).toEqual(expectedText); expect(myEditor.getFirstVisibleLine()).toBe(0); expect(myEditor.getLastVisibleLine()).toBe(3); }); it("should insert new line below the first line of the inline editor", function () { myEditor.setCursorPos({line: 0, ch: 3}); CommandManager.execute(Commands.EDIT_OPEN_LINE_BELOW, myEditor); var lines = content.split("\n"); lines.splice(1, 0, " "); var expectedText = lines.join("\n"); expect(myEditor.document.getText()).toEqual(expectedText); expect(myEditor.getFirstVisibleLine()).toBe(0); expect(myEditor.getLastVisibleLine()).toBe(3); }); it("should insert new line above the last line of the inline editor", function () { myEditor.setSelection({line: 2, ch: 0}, {line: 2, ch: 1}); CommandManager.execute(Commands.EDIT_OPEN_LINE_ABOVE, myEditor); var lines = content.split("\n"); lines.splice(2, 0, " "); var expectedText = lines.join("\n"); expect(myEditor.document.getText()).toEqual(expectedText); expect(myEditor.getFirstVisibleLine()).toBe(0); expect(myEditor.getLastVisibleLine()).toBe(3); }); it("should insert new line below the last line of the inline editor", function () { myEditor.setCursorPos({line: 3, ch: 0}); CommandManager.execute(Commands.EDIT_OPEN_LINE_BELOW, myEditor); var lines = content.split("\n"); lines.splice(3, 0, ""); var expectedText = lines.join("\n"); expect(myEditor.document.getText()).toEqual(expectedText); expect(myEditor.getFirstVisibleLine()).toBe(0); expect(myEditor.getLastVisibleLine()).toBe(3); }); it("should insert new indented line above the second line of the inline editor", function () { myEditor.setCursorPos({line: 1, ch: 5}); CommandManager.execute(Commands.EDIT_OPEN_LINE_ABOVE, myEditor); var lines = content.split("\n"); lines.splice(1, 0, " "); var expectedText = lines.join("\n"); expect(myEditor.document.getText()).toEqual(expectedText); expect(myEditor.getFirstVisibleLine()).toBe(0); expect(myEditor.getLastVisibleLine()).toBe(3); }); it("should insert new indented line below the second line of the inline editor", function () { myEditor.setCursorPos({line: 1, ch: 5}); CommandManager.execute(Commands.EDIT_OPEN_LINE_BELOW, myEditor); var lines = content.split("\n"); lines.splice(2, 0, " "); var expectedText = lines.join("\n"); expect(myEditor.document.getText()).toEqual(expectedText); expect(myEditor.getFirstVisibleLine()).toBe(0); expect(myEditor.getLastVisibleLine()).toBe(3); }); }); }); }); });