function Editor(document, makeMasterEditor, container, range, options) {
        var self = this;

        var isReadOnly = (options && options.isReadOnly) || !document.editable;

        _instances.push(this);

        // Attach to document: add ref & handlers
        this.document = document;
        document.addRef();

        if (container.jquery) {
            // CodeMirror wants a DOM element, not a jQuery wrapper
            container = container.get(0);
        }

        var $container = $(container);

        if (range) {    // attach this first: want range updated before we process a change
            this._visibleRange = new TextRange(document, range.startLine, range.endLine);
        }

        // store this-bound version of listeners so we can remove them later
        this._handleDocumentChange = this._handleDocumentChange.bind(this);
        this._handleDocumentDeleted = this._handleDocumentDeleted.bind(this);
        this._handleDocumentLanguageChanged = this._handleDocumentLanguageChanged.bind(this);
        this._doWorkingSetSync = this._doWorkingSetSync.bind(this);
        document.on("change", this._handleDocumentChange);
        document.on("deleted", this._handleDocumentDeleted);
        document.on("languageChanged", this._handleDocumentLanguageChanged);
        // To sync working sets if the view is for same doc across panes
        document.on("_dirtyFlagChange", this._doWorkingSetSync);

        var mode = this._getModeFromDocument();

        // (if makeMasterEditor, we attach the Doc back to ourselves below once we're fully initialized)

        this._inlineWidgets = [];
        this._inlineWidgetQueues = {};
        this._hideMarks = [];
        this._lastEditorWidth = null;

        this._$messagePopover = null;

        // To track which pane the editor is being attached to if it's a full editor
        this._paneId = null;

        // To track the parent editor ( host editor at that time of creation) of an inline editor
        this._hostEditor = null;

        // Editor supplies some standard keyboard behavior extensions of its own
        var codeMirrorKeyMap = {
            "Tab": function () { self._handleTabKey(); },
            "Shift-Tab": "indentLess",

            "Left": function (instance) {
                self._handleSoftTabNavigation(-1, "moveH");
            },
            "Right": function (instance) {
                self._handleSoftTabNavigation(1, "moveH");
            },
            "Backspace": function (instance) {
                self._handleSoftTabNavigation(-1, "deleteH");
            },
            "Delete": function (instance) {
                self._handleSoftTabNavigation(1, "deleteH");
            },
            "Esc": function (instance) {
                if (self.getSelections().length > 1) {
                    CodeMirror.commands.singleSelection(instance);
                } else {
                    self.removeAllInlineWidgets();
                }
            },
            "Home":      "goLineLeftSmart",
            "Cmd-Left":  "goLineLeftSmart",
            "End":       "goLineRight",
            "Cmd-Right": "goLineRight"
        };

        var currentOptions = this._currentOptions = _.zipObject(
            editorOptions,
            _.map(editorOptions, function (prefName) {
                return self._getOption(prefName);
            })
        );

        // When panes are created *after* the showLineNumbers option has been turned off
        //  we need to apply the show-line-padding class or the text will be juxtaposed
        //  to the edge of the editor which makes it not easy to read.  The code below to handle
        //  that the option change only applies the class to panes that have already been created
        // This line ensures that the class is applied to any editor created after the fact
        $container.toggleClass("show-line-padding", Boolean(!this._getOption("showLineNumbers")));

        // Create the CodeMirror instance
        // (note: CodeMirror doesn't actually require using 'new', but jslint complains without it)
        this._codeMirror = new CodeMirror(container, {
            autoCloseBrackets           : currentOptions[CLOSE_BRACKETS],
            autoCloseTags               : currentOptions[CLOSE_TAGS],
            coverGutterNextToScrollbar  : true,
            cursorScrollMargin          : 3,
            dragDrop                    : currentOptions[DRAG_DROP],
            electricChars               : true,
            extraKeys                   : codeMirrorKeyMap,
            highlightSelectionMatches   : currentOptions[HIGHLIGHT_MATCHES],
            indentUnit                  : currentOptions[USE_TAB_CHAR] ? currentOptions[TAB_SIZE] : currentOptions[SPACE_UNITS],
            indentWithTabs              : currentOptions[USE_TAB_CHAR],
            inputStyle                  : currentOptions[INPUT_STYLE],
            lineNumbers                 : currentOptions[SHOW_LINE_NUMBERS],
            lineWiseCopyCut             : currentOptions[LINEWISE_COPY_CUT],
            lineWrapping                : currentOptions[WORD_WRAP],
            matchBrackets               : { maxScanLineLength: 50000, maxScanLines: 1000 },
            matchTags                   : { bothTags: true },
            scrollPastEnd               : !range && currentOptions[SCROLL_PAST_END],
            showCursorWhenSelecting     : currentOptions[SHOW_CURSOR_SELECT],
            smartIndent                 : currentOptions[SMART_INDENT],
            styleActiveLine             : currentOptions[STYLE_ACTIVE_LINE],
            tabSize                     : currentOptions[TAB_SIZE],
            readOnly                    : isReadOnly
        });

        // Can't get CodeMirror's focused state without searching for
        // CodeMirror-focused. Instead, track focus via onFocus and onBlur
        // options and track state with this._focused
        this._focused = false;

        this._installEditorListeners();

        this._renderGutters();

        this.on("cursorActivity", function (event, editor) {
            self._handleCursorActivity(event);
        });
        this.on("keypress", function (event, editor, domEvent) {
            self._handleKeypressEvents(domEvent);
        });
        this.on("change", function (event, editor, changeList) {
            self._handleEditorChange(changeList);
        });
        this.on("focus", function (event, editor) {
            if (self._hostEditor) {
                // Mark the host editor as the master editor for the hosting document
                self._hostEditor.document._toggleMasterEditor(self._hostEditor);
            } else {
                // Set this full editor as master editor for the document
                self.document._toggleMasterEditor(self);
            }
        });

        // Set code-coloring mode BEFORE populating with text, to avoid a flash of uncolored text
        this._codeMirror.setOption("mode", mode);

        // Initially populate with text. This will send a spurious change event, so need to make
        // sure this is understood as a 'sync from document' case, not a genuine edit
        this._duringSync = true;
        this._resetText(document.getText());
        this._duringSync = false;

        if (range) {
            this._updateHiddenLines();
            this.setCursorPos(range.startLine, 0);
        }

        // Now that we're fully initialized, we can point the document back at us if needed
        if (makeMasterEditor) {
            document._makeEditable(this);
        }

        // Add scrollTop property to this object for the scroll shadow code to use
        Object.defineProperty(this, "scrollTop", {
            get: function () {
                return this._codeMirror.getScrollInfo().top;
            }
        });

        // Add an $el getter for Pane Views
        Object.defineProperty(this,  "$el", {
            get: function () {
                return $(this.getRootElement());
            }
        });
    }
Creates a new CodeMirror editor instance bound to the given Document. The Document need not have
a "master" Editor realized yet, even if makeMasterEditor is false; in that case, the first time
an edit occurs we will automatically ask EditorManager to create a "master" editor to render the
Document modifiable.

ALWAYS call destroy() when you are done with an Editor - otherwise it will leak a Document ref.

@constructor

@param {!Document} document
@param {!boolean} makeMasterEditor  If true, this Editor will set itself as the (secret) "master"
         Editor for the Document. If false, this Editor will attach to the Document as a "slave"/
         secondary editor.
@param {!jQueryObject|DomNode} container  Container to add the editor to.
@param {{startLine: number, endLine: number}=} range If specified, range of lines within the document
         to display in this editor. Inclusive.
@param {!Object} options If specified, contains editor options that can be passed to CodeMirror