Example #1
0
 $("#editor-holder").on("contextmenu", function (e) {
     if ($(e.target).parents(".CodeMirror-gutter").length !== 0) {
         return;
     }
     
     // Note: on mousedown before this event, CodeMirror automatically checks mouse pos, and
     // if not clicking on a selection moves the cursor to click location. When triggered
     // from keyboard, no pre-processing occurs and the cursor/selection is left as is.
     
     var editor = EditorManager.getFocusedEditor(),
         inlineWidget = EditorManager.getFocusedInlineWidget();
     
     if (editor) {
         // If there's just an insertion point select the word token at the cursor pos so
         // it's more clear what the context menu applies to.
         if (!editor.hasSelection()) {
             editor.selectWordAt(editor.getCursorPos());
             
             // Prevent menu from overlapping text by moving it down a little
             // Temporarily backout this change for now to help mitigate issue #1111,
             // which only happens if mouse is not over context menu. Better fix
             // requires change to bootstrap, which is too risky for now.
             //e.pageY += 6;
         }
         
         // Inline text editors have a different context menu (safe to assume it's not some other
         // type of inline widget since we already know an Editor has focus)
         if (inlineWidget) {
             inline_editor_cmenu.open(e);
         } else {
             editor_cmenu.open(e);
         }
     }
 });
    /**
     * Deletes the current line if there is no selection or the lines for the selection
     * (removing the end of line too)
     */
    function deleteCurrentLines(editor) {
        editor = editor || EditorManager.getFocusedEditor();
        if (!editor) {
            return;
        }

        var from,
            to,
            sel = editor.getSelection(),
            doc = editor.document;

        from = {line: sel.start.line, ch: 0};
        to = {line: sel.end.line + 1, ch: 0};
        if (to.line === editor.getLastVisibleLine() + 1) {
            // Instead of deleting the newline after the last line, delete the newline
            // before the first line--unless this is the entire visible content of the editor,
            // in which case just delete the line content.
            if (from.line > editor.getFirstVisibleLine()) {
                from.line -= 1;
                from.ch = doc.getLine(from.line).length;
            }
            to.line -= 1;
            to.ch = doc.getLine(to.line).length;
        }
        
        doc.replaceRange("", from, to);
    }
 /**
  * Unindent a line of text if no selection. Otherwise, unindent all lines in selection.
  */
 function unidentText() {
     var editor = EditorManager.getFocusedEditor();
     if (!editor) {
         return;
     }
     
     editor._codeMirror.execCommand("indentLess");
 }
 /**
  * Moves the selected text, or current line if no selection. The cursor/selection 
  * moves with the line/lines.
  * @param {Editor} editor - target editor
  * @param {Number} direction - direction of the move (-1,+1) => (Up,Down)
  */
 function moveLine(editor, direction) {
     editor = editor || EditorManager.getFocusedEditor();
     if (!editor) {
         return;
     }
     
     var doc = editor.document,
         sel = editor.getSelection(),
         originalSel = editor.getSelection(),
         hasSelection = (sel.start.line !== sel.end.line) || (sel.start.ch !== sel.end.ch);
     
     sel.start.ch = 0;
     // The end of the selection becomes the start of the next line, if it isn't already
     if (!hasSelection || sel.end.ch !== 0) {
         sel.end = {line: sel.end.line + 1, ch: 0};
     }
     
     // Make the move
     switch (direction) {
     case DIRECTION_UP:
         if (sel.start.line !== 0) {
             doc.batchOperation(function () {
                 var prevText = doc.getRange({ line: sel.start.line - 1, ch: 0 }, sel.start);
                 
                 if (sel.end.line === editor.lineCount()) {
                     prevText = "\n" + prevText.substring(0, prevText.length - 1);
                 }
                 
                 doc.replaceRange("", { line: sel.start.line - 1, ch: 0 }, sel.start);
                 doc.replaceRange(prevText, { line: sel.end.line - 1, ch: 0 });
                 
                 // Make sure CodeMirror hasn't expanded the selection to include
                 // the line we inserted below.
                 originalSel.start.line--;
                 originalSel.end.line--;
                 editor.setSelection(originalSel.start, originalSel.end);
             });
         }
         break;
     case DIRECTION_DOWN:
         if (sel.end.line < editor.lineCount()) {
             doc.batchOperation(function () {
                 var nextText = doc.getRange(sel.end, { line: sel.end.line + 1, ch: 0 });
                 
                 var deletionStart = sel.end;
                 if (sel.end.line === editor.lineCount() - 1) {
                     nextText += "\n";
                     deletionStart = { line: sel.end.line - 1, ch: doc.getLine(sel.end.line - 1).length };
                 }
 
                 doc.replaceRange("", deletionStart, { line: sel.end.line + 1, ch: 0 });
                 doc.replaceRange(nextText, { line: sel.start.line, ch: 0 });
             });
         }
         break;
     }
 }
Example #5
0
    /**
     * Creates a modal bar whose contents are the given template.
     * 
     * Dispatches one event:
     * - close - When the bar is closed, either via close() or via autoClose. After this event, the
     *     bar may remain visible and in the DOM while its closing animation is playing. However,
     *     by the time "close" is fired, the bar has been "popped out" of the layout and the
     *     editor scroll position has already been restored.
     * 
     * @constructor
     *
     * @param {string} template The HTML contents of the modal bar.
     * @param {boolean} autoClose If true, then close the dialog if the user hits Esc
     *      or if the bar loses focus.
     * @param {boolean} animate If true (the default), animate the dialog closed, otherwise
     *      close it immediately.
     */
    function ModalBar(template, autoClose, animate) {
        if (animate === undefined) {
            animate = true;
        }
        
        this._handleKeydown = this._handleKeydown.bind(this);
        this._handleFocusChange = this._handleFocusChange.bind(this);
        
        this._$root = $("<div class='modal-bar'/>")
            .html(template)
            .insertBefore("#editor-holder");

        if (animate) {
            this._$root.addClass("popout offscreen");
            // Forcing the renderer to do a layout, which will cause it to apply the transform for the "offscreen"
            // class, so it will animate when you remove the class.
            window.getComputedStyle(this._$root.get(0)).getPropertyValue("top");
            this._$root.removeClass("popout offscreen");
        }
        
        // If something *other* than an editor (like another modal bar) has focus, set the focus 
        // to the editor here, before opening up the new modal bar. This ensures that the old
        // focused item has time to react and close before the new modal bar is opened.
        // See bugs #4287 and #3424
        if (!EditorManager.getFocusedEditor()) {
            EditorManager.focusEditor();
        }
        
        if (autoClose) {
            this._autoClose = true;
            this._$root.on("keydown", this._handleKeydown);
            window.document.body.addEventListener("focusin", this._handleFocusChange, true);
                
            // Set focus to the first input field, or the first button if there is no input field.
            // TODO: remove this logic?
            var $firstInput = $("input[type='text']", this._$root).first();
            if ($firstInput.length > 0) {
                $firstInput.focus();
            } else {
                $("button", this._$root).first().focus();
            }
        }
        
        // Preserve scroll position of the current full editor across the editor refresh, adjusting for the 
        // height of the modal bar so the code doesn't appear to shift if possible.
        var fullEditor = EditorManager.getCurrentFullEditor(),
            scrollPos;
        if (fullEditor) {
            scrollPos = fullEditor.getScrollPos();
        }
        EditorManager.resizeEditor();
        if (fullEditor) {
            fullEditor._codeMirror.scrollTo(scrollPos.x, scrollPos.y + this.height());
        }
    }
Example #6
0
    Editor.prototype.focus = function () {
        // Capture the currently focused editor before making CodeMirror changes
        var previous = EditorManager.getFocusedEditor();

        // Prevent duplicate focusedEditorChanged events with this _internalFocus flag
        this._internalFocus = true;
        this._codeMirror.focus();
        this._internalFocus = false;

        EditorManager._doFocusedEditorChanged(this, previous);
    };
 /**
  * Invokes a language-specific block-comment/uncomment handler
  * @param {?Editor} editor If unspecified, applies to the currently focused editor
  */
 function blockComment(editor) {
     editor = editor || EditorManager.getFocusedEditor();
     if (!editor) {
         return;
     }
     
     var language = editor.getLanguageForSelection();
     
     if (language.blockComment) {
         blockCommentPrefixSuffix(editor, language.blockComment.prefix, language.blockComment.suffix, language.lineComment ? language.lineComment.prefix : null);
     }
 }
Example #8
0
    /**
    * Displays a non-modal embedded dialog above the code mirror editor that allows the user to do
    * a find operation across all files in the project.
    */
    function doFindInFiles() {

        var dialog = new FindInFilesDialog();
        
        // Default to searching for the current selection
        var currentEditor = EditorManager.getFocusedEditor();
        var initialString = currentEditor && currentEditor.getSelectedText();
        
        searchResults = [];
                            
        dialog.showDialog(initialString)
            .done(function (query) {
                if (query) {
                    StatusBar.showBusyIndicator(true);
                    var queryExpr = _getQueryRegExp(query);
                    FileIndexManager.getFileInfoList("all")
                        .done(function (fileListResult) {
                            Async.doInParallel(fileListResult, function (fileInfo) {
                                var result = new $.Deferred();
                                
                                DocumentManager.getDocumentForPath(fileInfo.fullPath)
                                    .done(function (doc) {
                                        var matches = _getSearchMatches(doc.getText(), queryExpr);
                                        
                                        if (matches && matches.length) {
                                            searchResults.push({
                                                fullPath: fileInfo.fullPath,
                                                matches: matches
                                            });
                                        }
                                        result.resolve();
                                    })
                                    .fail(function (error) {
                                        // Error reading this file. This is most likely because the file isn't a text file.
                                        // Resolve here so we move on to the next file.
                                        result.resolve();
                                    });
                                
                                return result.promise();
                            })
                                .done(function () {
                                    _showSearchResults(searchResults, query);
                                    StatusBar.hideBusyIndicator();
                                })
                                .fail(function () {
                                    console.log("find in files failed.");
                                    StatusBar.hideBusyIndicator();
                                });
                        });
                }
            });
    }
 /**
  * Invokes a language-specific line-comment/uncomment handler
  * @param {?Editor} editor If unspecified, applies to the currently focused editor
  */
 function lineComment(editor) {
     editor = editor || EditorManager.getFocusedEditor();
     if (!editor) {
         return;
     }
     
     var mode = editor.getModeForSelection();
     
     // Currently we only support languages with "//" commenting
     if (mode === "javascript" || mode === "less") {
         lineCommentSlashSlash(editor);
     }
 }
 /**
  * Invokes a language-specific block-comment/uncomment handler
  * @param {?Editor} editor If unspecified, applies to the currently focused editor
  */
 function blockComment(editor) {
     editor = editor || EditorManager.getFocusedEditor();
     if (!editor) {
         return;
     }
     
     var language = editor.getLanguageForSelection();
     
     if (language.hasBlockCommentSyntax()) {
         // getLineCommentPrefixes always return an array, and will be empty if no line comment syntax is defined
         blockCommentPrefixSuffix(editor, language.getBlockCommentPrefix(), language.getBlockCommentSuffix(), language.getLineCommentPrefixes());
     }
 }
 function handleUndoRedo(operation) {
     var editor = EditorManager.getFocusedEditor();
     var result = new $.Deferred();
     
     if (editor) {
         editor[operation]();
         result.resolve();
     } else {
         result.reject();
     }
     
     return result.promise();
 }
	function _handleSelectAll() {
        var result = new $.Deferred(),
            editor = EditorManager.getFocusedEditor();

        if (editor) {
            editor.selectAllNoScroll();
            result.resolve();
        } else {
            result.reject();    // command not handled
        }

        return result.promise();
    }
 /**
  * Invokes a language-specific line-comment/uncomment handler
  * @param {?Editor} editor If unspecified, applies to the currently focused editor
  */
 function lineComment(editor) {
     editor = editor || EditorManager.getFocusedEditor();
     if (!editor) {
         return;
     }
     
     var language = editor.getLanguageForSelection();
     
     if (language.hasLineCommentSyntax()) {
         lineCommentPrefix(editor, language.getLineCommentPrefixes());
     } else if (language.hasBlockCommentSyntax()) {
         lineCommentPrefixSuffix(editor, language.getBlockCommentPrefix(), language.getBlockCommentSuffix());
     }
 }
Example #14
0
    /** Launches CodeMirror's basic Find-within-single-editor feature */
    function _launchFind() {
        var editor = EditorManager.getFocusedEditor();
        if (editor) {
            var codeMirror = editor._codeMirror;

            // Bring up CodeMirror's existing search bar UI
            codeMirror.execCommand("find");

            // Prepopulate the search field with the current selection, if any
            $(".CodeMirror-dialog input[type='text']")
                .attr("value", codeMirror.getSelection())
                .get(0).select();
        }
    }
Example #15
0
    /**
     * Explicitly start a new session. If we have an existing session,
     * then close the current one and restart a new one.
     * @param {Editor} editor
     */
    function _startNewSession(editor) {
        if (!editor) {
            editor = EditorManager.getFocusedEditor();
        }

        if (editor) {
            lastChar = null;
            if (_inSession(editor)) {
                _endSession();
            }
            // Begin a new explicit session
            _beginSession(editor);
        }
    }
 /** Invokes a language-specific line-comment/uncomment handler */
 function lineComment() {
     var editor = EditorManager.getFocusedEditor();
     if (!editor) {
         return;
     }
     
     // TODO: use mode *at cursor location*, so we can support mixed-mode e.g. JS in script blocks
     var mode = editor._codeMirror.getOption("mode");
     
     // Currently we only support languages with "//" commenting
     if (mode === "javascript" || mode === "less") {
         lineCommentSlashSlash(editor);
     }
 }
Example #17
0
    function _launchFind() {
        var editor = EditorManager.getFocusedEditor();
        if (editor) {
            var codeMirror = editor._codeMirror;

            // Bring up CodeMirror's existing search bar UI
            clearSearch(codeMirror);
            doSearch(codeMirror);

            // Prepopulate the search field with the current selection, if any
            getDialogTextField()
                .attr("value", codeMirror.getSelection())
                .get(0).select();
        }
    }
 /**
  * Invokes a language-specific block-comment/uncomment handler
  * @param {?Editor} editor If unspecified, applies to the currently focused editor
  */
 function blockComment(editor) {
     editor = editor || EditorManager.getFocusedEditor();
     if (!editor) {
         return;
     }
     
     var mode = editor.getModeForSelection();
     
     if (mode === "javascript" || mode === "less") {
         blockCommentPrefixSuffix(editor, "/*", "*/", true);
     } else if (mode === "css") {
         blockCommentPrefixSuffix(editor, "/*", "*/", false);
     } else if (mode === "html") {
         blockCommentPrefixSuffix(editor, "<!--", "-->", false);
     }
 }
 /**
  * Invokes a language-specific line-comment/uncomment handler
  * @param {?Editor} editor If unspecified, applies to the currently focused editor
  */
 function lineComment(editor) {
     editor = editor || EditorManager.getFocusedEditor();
     if (!editor) {
         return;
     }
     
     var mode = editor.getModeForSelection();
     
     // Currently we only support languages with "//" commenting
     if (mode === "javascript" || mode === "less") {
         lineCommentSlashSlash(editor);
     } else if (mode === "css") {
         lineCommentPrefixSuffix(editor, "/*", "*/");
     } else if (mode === "html") {
         lineCommentPrefixSuffix(editor, "<!--", "-->");
     }
 }
 function selectLine(editor) {
     editor = editor || EditorManager.getFocusedEditor();
     if (editor) {
         var sel  = editor.getSelection();
         var from = {line: sel.start.line, ch: 0};
         var to   = {line: sel.end.line + 1, ch: 0};
         
         if (to.line === editor.getLastVisibleLine() + 1) {
             // Last line: select to end of line instead of start of (hidden/nonexistent) following line,
             // which due to how CM clips coords would only work some of the time
             to.line -= 1;
             to.ch = editor.document.getLine(to.line).length;
         }
         
         editor.setSelection(from, to);
     }
 }
 /**
  * Saves the given file. If no file specified, assumes the current document.
  * @param {?{doc: Document}} commandData  Document to close, or null
  * @return {$.Promise} a promise that is resolved after the save completes
  */
 function handleFileSave(commandData) {
     // Default to current document if doc is null
     var doc = null;
     if (commandData) {
         doc = commandData.doc;
     }
     if (!doc) {
         var focusedEditor = EditorManager.getFocusedEditor();
         
         if (focusedEditor) {
             doc = focusedEditor.document;
         }
         
         // doc may still be null, e.g. if no editors are open, but doSave() does a null check on
         // doc and makes sure the document is dirty before saving.
     }
     
     return doSave(doc);
 }
Example #22
0
 /**
  * @constructor
  *
  * Creates a modal bar whose contents are the given template.
  * @param {string} template The HTML contents of the modal bar.
  * @param {boolean} autoClose If true, then close the dialog if the user hits RETURN or ESC 
  *      in the first input field, or if the modal bar loses focus to an outside item. Dispatches 
  *      jQuery events for these cases: "closeOk" on RETURN, "closeCancel" on ESC, and "closeBlur" 
  *      on focus loss.
  */
 function ModalBar(template, autoClose) {
     this._handleInputKeydown = this._handleInputKeydown.bind(this);
     this._handleFocusChange = this._handleFocusChange.bind(this);
     
     this._$root = $("<div class='modal-bar'/>")
         .html(template)
         .insertBefore("#editor-holder");
     
     // If something *other* than an editor (like another modal bar) has focus, set the focus 
     // to the editor here, before opening up the new modal bar. This ensures that the old
     // focused item has time to react and close before the new modal bar is opened.
     // See bugs #4287 and #3424
     if (!EditorManager.getFocusedEditor()) {
         EditorManager.focusEditor();
     }
     
     if (autoClose) {
         this._autoClose = true;
         var $firstInput = this._getFirstInput()
             .on("keydown", this._handleInputKeydown);
         window.document.body.addEventListener("focusin", this._handleFocusChange, true);
             
         // Set focus to the first input field, or the first button if there is no input field.
         if ($firstInput.length > 0) {
             $firstInput.focus();
         } else {
             $("button", this._$root).first().focus();
         }
     }
     
     // Preserve scroll position of the current full editor across the editor refresh, adjusting for the 
     // height of the modal bar so the code doesn't appear to shift if possible.
     var fullEditor = EditorManager.getCurrentFullEditor(),
         scrollPos;
     if (fullEditor) {
         scrollPos = fullEditor.getScrollPos();
     }
     EditorManager.resizeEditor();
     if (fullEditor) {
         fullEditor._codeMirror.scrollTo(scrollPos.x, scrollPos.y + this.height());
     }
 }
Example #23
0
    /**
     * Explicitly start a new session. If we have an existing session,
     * then close the current one and restart a new one.
     * @param {Editor} editor
     */
    function _startNewSession(editor) {
        if (codeHintOpened) {
            return;
        }

        if (!editor) {
            editor = EditorManager.getFocusedEditor();
        }

        if (editor) {
            lastChar = null;
            if (_inSession(editor)) {
                _endSession();
            }
            // Begin a new explicit session
            _beginSession(editor);

            codeHintOpened = true;
        }
    }
Example #24
0
 /**
  * Duplicates the selected text, or current line if no selection. The cursor/selection is left
  * on the second copy.
  */
 function duplicateText(editor) {
     editor = editor || EditorManager.getFocusedEditor();
     if (!editor) {
         return;
     }
     
     var sel = editor.getSelection();
     
     var hasSelection = (sel.start.line !== sel.end.line) || (sel.start.ch !== sel.end.ch);
     
     if (!hasSelection) {
         sel.start.ch = 0;
         sel.end = {line: sel.start.line + 1, ch: 0};
     }
     
     // Make the edit
     var doc = editor.document;
     
     var selectedText = doc.getRange(sel.start, sel.end);
     doc.replaceRange(selectedText, sel.start);
 }
Example #25
0
 $("#editor-holder").on("contextmenu", function (e) {
     if ($(e.target).parents(".CodeMirror-gutter").length !== 0) {
         return;
     }
     
     // Note: on mousedown before this event, CodeMirror automatically checks mouse pos, and
     // if not clicking on a selection moves the cursor to click location. When triggered
     // from keyboard, no pre-processing occurs and the cursor/selection is left as is.
     
     var editor = EditorManager.getFocusedEditor();
     if (editor) {
         // If there's just an insertion point select the word token at the cursor pos so
         // it's more clear what the context menu applies to.
         if (!editor.hasSelection()) {
             editor.selectWordAt(editor.getCursorPos());
             
             // Prevent menu from overlapping text by moving it down a little
             e.pageY += 6;
         }
         
         editor_cmenu.open(e);
     }
 });
 /**
  * Inserts a new and smart indented line above/below the selected text, or current line if no selection.
  * The cursor is moved in the new line.
  * @param {Editor} editor - target editor
  * @param {Number} direction - direction where to place the new line (-1,+1) => (Up,Down)
  */
 function openLine(editor, direction) {
     editor = editor || EditorManager.getFocusedEditor();
     if (!editor) {
         return;
     }
     
     var sel            = editor.getSelection(),
         hasSelection   = (sel.start.line !== sel.end.line) || (sel.start.ch !== sel.end.ch),
         isInlineWidget = !!EditorManager.getFocusedInlineWidget(),
         lastLine       = editor.getLastVisibleLine(),
         cm             = editor._codeMirror,
         doc            = editor.document,
         line;
     
     // Insert the new line
     switch (direction) {
     case DIRECTION_UP:
         line = sel.start.line;
         break;
     case DIRECTION_DOWN:
         line = sel.end.line;
         if (!(hasSelection && sel.end.ch === 0)) {
             // If not linewise selection
             line++;
         }
         break;
     }
     
     if (line > lastLine && isInlineWidget) {
         doc.replaceRange("\n", {line: line - 1, ch: doc.getLine(line - 1).length}, null, "+input");
     } else {
         doc.replaceRange("\n", {line: line, ch: 0}, null, "+input");
     }
     cm.indentLine(line, "smart", false);
     editor.setSelection({line: line, ch: null});
 }
Example #27
0
    /**
     * Deletes the current line if there is no selection or the lines for the selection
     * (removing the end of line too)
     */
    function deleteCurrentLines(editor) {
        editor = editor || EditorManager.getFocusedEditor();
        if (!editor) {
            return;
        }

        var from,
            to,
            sel = editor.getSelection(),
            doc = editor.document,
            endLine;
        
        from = {line: sel.start.line, ch: 0};
        
        if (sel.end.line === editor.getLastVisibleLine()) {
            // Instead of deleting the newline after the last line, delete the newline
            // before the first line--unless this is the entire visible content of the editor,
            // in which case just delete the line content.
            if (from.line > editor.getFirstVisibleLine()) {
                from.line -= 1;
                from.ch = doc.getLine(from.line).length;
            }
            to = {line: sel.end.line, ch: doc.getLine(sel.end.line).length};
        } else {
            // Don't delete the line that the selection ends on if the selection
            // starts on a previous line and ends right at the beginning of the
            // last line.
            endLine = sel.end.line + 1;
            if (sel.start.line < sel.end.line && sel.end.ch === 0) {
                endLine--;
            }
            to = {line: endLine, ch: 0};
        }
        
        doc.replaceRange("", from, to);
    }
    /**
     * Duplicates the selected text, or current line if no selection. The cursor/selection is left
     * on the second copy.
     */
    function duplicateText(editor) {
        editor = editor || EditorManager.getFocusedEditor();
        if (!editor) {
            return;
        }

        var sel = editor.getSelection(),
            hasSelection = (sel.start.line !== sel.end.line) || (sel.start.ch !== sel.end.ch),
            delimiter = "";

        if (!hasSelection) {
            sel.start.ch = 0;
            sel.end = {line: sel.start.line + 1, ch: 0};
            if (sel.end.line === editor.lineCount()) {
                delimiter = "\n";
            }
        }

        // Make the edit
        var doc = editor.document;

        var selectedText = doc.getRange(sel.start, sel.end) + delimiter;
        doc.replaceRange(selectedText, sel.start);
    }
 /**
  * Moves the selected text, or current line if no selection. The cursor/selection 
  * moves with the line/lines.
  * @param {Editor} editor - target editor
  * @param {Number} direction - direction of the move (-1,+1) => (Up,Down)
  */
 function moveLine(editor, direction) {
     editor = editor || EditorManager.getFocusedEditor();
     if (!editor) {
         return;
     }
     
     var doc = editor.document,
         sel = editor.getSelection(),
         originalSel    = editor.getSelection(),
         hasSelection   = (sel.start.line !== sel.end.line) || (sel.start.ch !== sel.end.ch),
         isInlineWidget = !!EditorManager.getFocusedInlineWidget(),
         firstLine      = editor.getFirstVisibleLine(),
         lastLine       = editor.getLastVisibleLine(),
         totalLines     = editor.lineCount(),
         lineLength     = 0;
     
     sel.start.ch = 0;
     // The end of the selection becomes the start of the next line, if it isn't already
     if (!hasSelection || sel.end.ch !== 0) {
         sel.end = {line: sel.end.line + 1, ch: 0};
     }
     
     // Make the move
     switch (direction) {
     case DIRECTION_UP:
         if (sel.start.line !== firstLine) {
             doc.batchOperation(function () {
                 var prevText = doc.getRange({ line: sel.start.line - 1, ch: 0 }, sel.start);
                 
                 if (sel.end.line === lastLine + 1) {
                     if (isInlineWidget) {
                         prevText   = prevText.substring(0, prevText.length - 1);
                         lineLength = doc.getLine(sel.end.line - 1).length;
                         doc.replaceRange("\n", { line: sel.end.line - 1, ch: lineLength });
                     } else {
                         prevText = "\n" + prevText.substring(0, prevText.length - 1);
                     }
                 }
                 
                 doc.replaceRange("", { line: sel.start.line - 1, ch: 0 }, sel.start);
                 doc.replaceRange(prevText, { line: sel.end.line - 1, ch: 0 });
                 
                 // Make sure CodeMirror hasn't expanded the selection to include
                 // the line we inserted below.
                 originalSel.start.line--;
                 originalSel.end.line--;
             });
 
             // Update the selection after the document batch so it's not blown away on resynchronization
             // if this editor is not the master editor.
             editor.setSelection(originalSel.start, originalSel.end);
         }
         break;
     case DIRECTION_DOWN:
         if (sel.end.line <= lastLine) {
             doc.batchOperation(function () {
                 var nextText      = doc.getRange(sel.end, { line: sel.end.line + 1, ch: 0 }),
                     deletionStart = sel.end;
                 
                 if (sel.end.line === lastLine) {
                     if (isInlineWidget) {
                         if (sel.end.line === totalLines - 1) {
                             nextText += "\n";
                         }
                         lineLength = doc.getLine(sel.end.line - 1).length;
                         doc.replaceRange("\n", { line: sel.end.line, ch: doc.getLine(sel.end.line).length });
                     } else {
                         nextText     += "\n";
                         deletionStart = { line: sel.end.line - 1, ch: doc.getLine(sel.end.line - 1).length };
                     }
                 }
 
                 doc.replaceRange("", deletionStart, { line: sel.end.line + 1, ch: 0 });
                 if (lineLength) {
                     doc.replaceRange("", { line: sel.end.line - 1, ch: lineLength }, { line: sel.end.line, ch: 0 });
                 }
                 doc.replaceRange(nextText, { line: sel.start.line, ch: 0 });
             });
         }
         break;
     }
 }
Example #30
0
 function _handleSelectAll() {
     var editor = EditorManager.getFocusedEditor();
     if (editor) {
         editor._selectAllVisible();
     }
 }