diff --git a/apm/package.json b/apm/package.json index b8dda21ea..2e6b0b8ea 100644 --- a/apm/package.json +++ b/apm/package.json @@ -6,6 +6,6 @@ "url": "https://github.com/atom/atom.git" }, "dependencies": { - "atom-package-manager": "1.5.0" + "atom-package-manager": "1.6.0" } } diff --git a/build/Gruntfile.coffee b/build/Gruntfile.coffee index 26d9c2f42..63afc2fd7 100644 --- a/build/Gruntfile.coffee +++ b/build/Gruntfile.coffee @@ -14,6 +14,8 @@ _ = require 'underscore-plus' packageJson = require '../package.json' module.exports = (grunt) -> + require('time-grunt')(grunt) + grunt.loadNpmTasks('grunt-babel') grunt.loadNpmTasks('grunt-coffeelint') grunt.loadNpmTasks('grunt-lesslint') diff --git a/build/package.json b/build/package.json index fd7d29d80..d5c780c08 100644 --- a/build/package.json +++ b/build/package.json @@ -37,6 +37,7 @@ "runas": "^3.1", "tello": "1.0.5", "temp": "~0.8.1", + "time-grunt": "1.2.2", "underscore-plus": "1.x", "unzip": "~0.1.9", "vm-compatibility-layer": "~0.1.0", diff --git a/package.json b/package.json index 72c8a14ae..d6eefcc7c 100644 --- a/package.json +++ b/package.json @@ -22,13 +22,13 @@ "clear-cut": "^2.0.1", "coffee-script": "1.8.0", "color": "^0.7.3", - "event-kit": "^1.3.0", + "event-kit": "^1.5.0", "find-parent-dir": "^0.3.0", "first-mate": "^5.1.1", "fs-plus": "^2.8.0", "fstream": "0.1.24", "fuzzaldrin": "^2.1", - "git-utils": "^4.0.7", + "git-utils": "^4.1.0", "grim": "1.5.0", "jasmine-json": "~0.0", "jasmine-tagged": "^1.1.4", @@ -52,7 +52,7 @@ "service-hub": "^0.7.0", "source-map-support": "^0.3.2", "temp": "0.8.1", - "text-buffer": "8.1.3", + "text-buffer": "8.1.4", "typescript-simple": "1.0.0", "underscore-plus": "^1.6.6", "yargs": "^3.23.0" @@ -122,23 +122,23 @@ "language-csharp": "0.11.0", "language-css": "0.36.0", "language-gfm": "0.82.0", - "language-git": "0.11.1", + "language-git": "0.11.0", "language-go": "0.41.0", "language-html": "0.43.1", "language-hyperlink": "0.16.0", "language-java": "0.17.0", - "language-javascript": "0.104.0", + "language-javascript": "0.105.0", "language-json": "0.17.2", "language-less": "0.29.0", "language-make": "0.21.0", "language-mustache": "0.13.0", "language-objective-c": "0.15.1", "language-perl": "0.32.0", - "language-php": "0.34.0", + "language-php": "0.36.0", "language-property-list": "0.8.0", "language-python": "0.42.1", - "language-ruby": "0.65.0", - "language-ruby-on-rails": "0.24.0", + "language-ruby": "0.67.0", + "language-ruby-on-rails": "0.25.0", "language-sass": "0.45.0", "language-shellscript": "0.21.0", "language-source": "0.9.0", diff --git a/script/bootstrap b/script/bootstrap index 8314b9cb0..5f9241a3d 100755 --- a/script/bootstrap +++ b/script/bootstrap @@ -5,8 +5,16 @@ var verifyRequirements = require('./utils/verify-requirements'); var safeExec = require('./utils/child-process-wrapper.js').safeExec; var path = require('path'); +var t0, t1 + // Executes an array of commands one by one. function executeCommands(commands, done, index) { + if (index != undefined) { + t1 = Date.now() + console.log("=> Took " + (t1 - t0) + "ms."); + console.log(); + } + index = (index == undefined ? 0 : index); if (index < commands.length) { var command = commands[index]; @@ -17,6 +25,7 @@ function executeCommands(commands, done, index) { options = command.options; command = command.command; } + t0 = Date.now() safeExec(command, options, executeCommands.bind(this, commands, done, index + 1)); } else @@ -96,7 +105,10 @@ function bootstrap() { message: 'Installing apm...', options: apmInstallOptions }, - apmPath + ' clean' + apmFlags, + { + command: apmPath + ' clean' + apmFlags, + message: 'Deleting old packages...' + }, moduleInstallCommand, dedupeApmCommand + ' ' + packagesToDedupe.join(' '), ]; diff --git a/spec/fake-lines-yardstick.coffee b/spec/fake-lines-yardstick.coffee index da5f8327e..a2568b959 100644 --- a/spec/fake-lines-yardstick.coffee +++ b/spec/fake-lines-yardstick.coffee @@ -19,9 +19,8 @@ class FakeLinesYardstick setScopedCharacterWidth: (scopeNames, character, width) -> @getScopedCharacterWidths(scopeNames)[character] = width - pixelPositionForScreenPosition: (screenPosition, clip=true) -> + pixelPositionForScreenPosition: (screenPosition) -> screenPosition = Point.fromObject(screenPosition) - screenPosition = @model.clipScreenPosition(screenPosition) if clip targetRow = screenPosition.row targetColumn = screenPosition.column diff --git a/spec/integration/startup-spec.coffee b/spec/integration/startup-spec.coffee index 799c7685f..da4e08ae2 100644 --- a/spec/integration/startup-spec.coffee +++ b/spec/integration/startup-spec.coffee @@ -125,6 +125,27 @@ describe "Starting Atom", -> .treeViewRootDirectories() .then ({value}) -> expect(value).toEqual([otherTempDirPath]) + it "opens the new window offset from the other window", -> + runAtom [path.join(tempDirPath, "new-file")], {ATOM_HOME: atomHome}, (client) -> + win0Position = null + win1Position = null + client + .waitForWindowCount(1, 10000) + .execute -> atom.getPosition() + .then ({value}) -> win0Position = value + .waitForNewWindow(-> + @startAnotherAtom([path.join(temp.mkdirSync("a-third-dir"), "a-file")], ATOM_HOME: atomHome) + , 5000) + .waitForWindowCount(2, 10000) + .execute -> atom.getPosition() + .then ({value}) -> win1Position = value + .then -> + expect(win1Position.x).toBeGreaterThan(win0Position.x) + # Ideally we'd test the y coordinate too, but if the window's + # already as tall as it can be, then OS X won't move it down outside + # the screen. + # expect(win1Position.y).toBeGreaterThan(win0Position.y) + describe "reopening a directory that was previously opened", -> it "remembers the state of the window", -> runAtom [tempDirPath], {ATOM_HOME: atomHome}, (client) -> diff --git a/spec/lines-yardstick-spec.coffee b/spec/lines-yardstick-spec.coffee index 74f5fca6a..3520d6935 100644 --- a/spec/lines-yardstick-spec.coffee +++ b/spec/lines-yardstick-spec.coffee @@ -1,5 +1,6 @@ LinesYardstick = require "../src/lines-yardstick" {toArray} = require 'underscore-plus' +{Point} = require 'text-buffer' describe "LinesYardstick", -> [editor, mockLineNodesProvider, createdLineNodes, linesYardstick, buildLineNode] = [] @@ -62,12 +63,12 @@ describe "LinesYardstick", -> } """ - expect(linesYardstick.pixelPositionForScreenPosition([0, 0])).toEqual({left: 0, top: 0}) - expect(linesYardstick.pixelPositionForScreenPosition([0, 1])).toEqual({left: 7, top: 0}) - expect(linesYardstick.pixelPositionForScreenPosition([0, 5])).toEqual({left: 37.78125, top: 0}) - expect(linesYardstick.pixelPositionForScreenPosition([1, 6])).toEqual({left: 43.171875, top: 14}) - expect(linesYardstick.pixelPositionForScreenPosition([1, 9])).toEqual({left: 72.171875, top: 14}) - expect(linesYardstick.pixelPositionForScreenPosition([2, Infinity])).toEqual({left: 287.859375, top: 28}) + expect(linesYardstick.pixelPositionForScreenPosition(Point(0, 0))).toEqual({left: 0, top: 0}) + expect(linesYardstick.pixelPositionForScreenPosition(Point(0, 1))).toEqual({left: 7, top: 0}) + expect(linesYardstick.pixelPositionForScreenPosition(Point(0, 5))).toEqual({left: 37.78125, top: 0}) + expect(linesYardstick.pixelPositionForScreenPosition(Point(1, 6))).toEqual({left: 43.171875, top: 14}) + expect(linesYardstick.pixelPositionForScreenPosition(Point(1, 9))).toEqual({left: 72.171875, top: 14}) + expect(linesYardstick.pixelPositionForScreenPosition(Point(2, Infinity))).toEqual({left: 287.859375, top: 28}) it "reuses already computed pixel positions unless it is invalidated", -> atom.styles.addStyleSheet """ @@ -77,9 +78,9 @@ describe "LinesYardstick", -> } """ - expect(linesYardstick.pixelPositionForScreenPosition([1, 2])).toEqual({left: 19.203125, top: 14}) - expect(linesYardstick.pixelPositionForScreenPosition([2, 6])).toEqual({left: 57.609375, top: 28}) - expect(linesYardstick.pixelPositionForScreenPosition([5, 10])).toEqual({left: 95.609375, top: 70}) + expect(linesYardstick.pixelPositionForScreenPosition(Point(1, 2))).toEqual({left: 19.203125, top: 14}) + expect(linesYardstick.pixelPositionForScreenPosition(Point(2, 6))).toEqual({left: 57.609375, top: 28}) + expect(linesYardstick.pixelPositionForScreenPosition(Point(5, 10))).toEqual({left: 95.609375, top: 70}) atom.styles.addStyleSheet """ * { @@ -87,15 +88,15 @@ describe "LinesYardstick", -> } """ - expect(linesYardstick.pixelPositionForScreenPosition([1, 2])).toEqual({left: 19.203125, top: 14}) - expect(linesYardstick.pixelPositionForScreenPosition([2, 6])).toEqual({left: 57.609375, top: 28}) - expect(linesYardstick.pixelPositionForScreenPosition([5, 10])).toEqual({left: 95.609375, top: 70}) + expect(linesYardstick.pixelPositionForScreenPosition(Point(1, 2))).toEqual({left: 19.203125, top: 14}) + expect(linesYardstick.pixelPositionForScreenPosition(Point(2, 6))).toEqual({left: 57.609375, top: 28}) + expect(linesYardstick.pixelPositionForScreenPosition(Point(5, 10))).toEqual({left: 95.609375, top: 70}) linesYardstick.invalidateCache() - expect(linesYardstick.pixelPositionForScreenPosition([1, 2])).toEqual({left: 24, top: 14}) - expect(linesYardstick.pixelPositionForScreenPosition([2, 6])).toEqual({left: 72, top: 28}) - expect(linesYardstick.pixelPositionForScreenPosition([5, 10])).toEqual({left: 120, top: 70}) + expect(linesYardstick.pixelPositionForScreenPosition(Point(1, 2))).toEqual({left: 24, top: 14}) + expect(linesYardstick.pixelPositionForScreenPosition(Point(2, 6))).toEqual({left: 72, top: 28}) + expect(linesYardstick.pixelPositionForScreenPosition(Point(5, 10))).toEqual({left: 120, top: 70}) it "correctly handles RTL characters", -> atom.styles.addStyleSheet """ @@ -106,13 +107,13 @@ describe "LinesYardstick", -> """ editor.setText("السلام عليكم") - expect(linesYardstick.pixelPositionForScreenPosition([0, 0]).left).toBe 0 - expect(linesYardstick.pixelPositionForScreenPosition([0, 1]).left).toBe 8 - expect(linesYardstick.pixelPositionForScreenPosition([0, 2]).left).toBe 16 - expect(linesYardstick.pixelPositionForScreenPosition([0, 5]).left).toBe 33 - expect(linesYardstick.pixelPositionForScreenPosition([0, 7]).left).toBe 50 - expect(linesYardstick.pixelPositionForScreenPosition([0, 9]).left).toBe 67 - expect(linesYardstick.pixelPositionForScreenPosition([0, 11]).left).toBe 84 + expect(linesYardstick.pixelPositionForScreenPosition(Point(0, 0)).left).toBe 0 + expect(linesYardstick.pixelPositionForScreenPosition(Point(0, 1)).left).toBe 8 + expect(linesYardstick.pixelPositionForScreenPosition(Point(0, 2)).left).toBe 16 + expect(linesYardstick.pixelPositionForScreenPosition(Point(0, 5)).left).toBe 33 + expect(linesYardstick.pixelPositionForScreenPosition(Point(0, 7)).left).toBe 50 + expect(linesYardstick.pixelPositionForScreenPosition(Point(0, 9)).left).toBe 67 + expect(linesYardstick.pixelPositionForScreenPosition(Point(0, 11)).left).toBe 84 it "doesn't report a width greater than 0 when the character to measure is at the beginning of a text node", -> # This spec documents what seems to be a bug in Chromium, because we'd @@ -137,9 +138,9 @@ describe "LinesYardstick", -> editor.setText(text) - expect(linesYardstick.pixelPositionForScreenPosition([0, 35]).left).toBe 230.90625 - expect(linesYardstick.pixelPositionForScreenPosition([0, 36]).left).toBe 237.5 - expect(linesYardstick.pixelPositionForScreenPosition([0, 37]).left).toBe 244.09375 + expect(linesYardstick.pixelPositionForScreenPosition(Point(0, 35)).left).toBe 230.90625 + expect(linesYardstick.pixelPositionForScreenPosition(Point(0, 36)).left).toBe 237.5 + expect(linesYardstick.pixelPositionForScreenPosition(Point(0, 37)).left).toBe 244.09375 describe "::screenPositionForPixelPosition(pixelPosition)", -> it "converts pixel positions to screen positions", -> diff --git a/spec/text-editor-component-spec.js b/spec/text-editor-component-spec.js index d5e9f5425..0546926e3 100644 --- a/spec/text-editor-component-spec.js +++ b/spec/text-editor-component-spec.js @@ -4567,6 +4567,13 @@ describe('TextEditorComponent', function () { }) }) + describe('::pixelPositionForScreenPosition()', () => { + it('returns the correct horizontal position, even if it is on a row that has not yet been rendered (regression)', () => { + editor.setTextInBufferRange([[5, 0], [6, 0]], 'hello world\n') + expect(wrapperNode.pixelPositionForScreenPosition([5, Infinity]).left).toBeGreaterThan(0) + }) + }) + describe('middle mouse paste on Linux', function () { let originalPlatform diff --git a/src/browser/atom-application.coffee b/src/browser/atom-application.coffee index e720597e3..a5a535b93 100644 --- a/src/browser/atom-application.coffee +++ b/src/browser/atom-application.coffee @@ -167,7 +167,7 @@ class AtomApplication safeMode: @focusedWindow()?.safeMode @on 'application:quit', -> app.quit() - @on 'application:new-window', -> @openPath(_.extend(windowDimensions: @focusedWindow()?.getDimensions(), getLoadSettings())) + @on 'application:new-window', -> @openPath(getLoadSettings()) @on 'application:new-file', -> (@focusedWindow() ? this).openPath() @on 'application:open', -> @promptForPathToOpen('all', getLoadSettings()) @on 'application:open-file', -> @promptForPathToOpen('file', getLoadSettings()) @@ -229,7 +229,7 @@ class AtomApplication @openUrl({urlToOpen, @devMode, @safeMode}) app.on 'activate-with-no-open-windows', (event) => - event.preventDefault() + event?.preventDefault() @emit('application:new-window') # A request from the associated render process to open a new render process. @@ -360,6 +360,23 @@ class AtomApplication focusedWindow: -> _.find @windows, (atomWindow) -> atomWindow.isFocused() + # Get the platform-specific window offset for new windows. + getWindowOffsetForCurrentPlatform: -> + offsetByPlatform = + darwin: 22 + win32: 26 + offsetByPlatform[process.platform] ? 0 + + # Get the dimensions for opening a new window by cascading as appropriate to + # the platform. + getDimensionsForNewWindow: -> + dimensions = (@focusedWindow() ? @lastFocusedWindow)?.getDimensions() + offset = @getWindowOffsetForCurrentPlatform() + if dimensions? and offset? + dimensions.x += offset + dimensions.y += offset + dimensions + # Public: Opens a single path, in an existing window if possible. # # options - @@ -370,7 +387,7 @@ class AtomApplication # :safeMode - Boolean to control the opened window's safe mode. # :profileStartup - Boolean to control creating a profile of the startup time. # :window - {AtomWindow} to open file paths in. - openPath: ({pathToOpen, pidToKillWhenClosed, newWindow, devMode, safeMode, profileStartup, window}) -> + openPath: ({pathToOpen, pidToKillWhenClosed, newWindow, devMode, safeMode, profileStartup, window} = {}) -> @openPaths({pathsToOpen: [pathToOpen], pidToKillWhenClosed, newWindow, devMode, safeMode, profileStartup, window}) # Public: Opens multiple paths, in existing windows if possible. @@ -417,6 +434,7 @@ class AtomApplication windowInitializationScript ?= require.resolve('../initialize-application-window') resourcePath ?= @resourcePath + windowDimensions ?= @getDimensionsForNewWindow() openedWindow = new AtomWindow({locationsToOpen, windowInitializationScript, resourcePath, devMode, safeMode, windowDimensions, profileStartup}) if pidToKillWhenClosed? diff --git a/src/git-repository.coffee b/src/git-repository.coffee index 1663f9ad4..ee27f87a5 100644 --- a/src/git-repository.coffee +++ b/src/git-repository.coffee @@ -463,8 +463,12 @@ class GitRepository refreshStatus: -> @handlerPath ?= require.resolve('./repository-status-handler') + relativeProjectPaths = @project?.getPaths() + .map (path) => @relativize(path) + .filter (path) -> path.length > 0 + @statusTask?.terminate() - @statusTask = Task.once @handlerPath, @getPath(), ({statuses, upstream, branch, submodules}) => + @statusTask = Task.once @handlerPath, @getPath(), relativeProjectPaths, ({statuses, upstream, branch, submodules}) => statusesUnchanged = _.isEqual(statuses, @statuses) and _.isEqual(upstream, @upstream) and _.isEqual(branch, @branch) and diff --git a/src/lines-yardstick.coffee b/src/lines-yardstick.coffee index bd8219e81..9edbbe17a 100644 --- a/src/lines-yardstick.coffee +++ b/src/lines-yardstick.coffee @@ -77,10 +77,7 @@ class LinesYardstick else Point(row, column) - pixelPositionForScreenPosition: (screenPosition, clip=true) -> - screenPosition = Point.fromObject(screenPosition) - screenPosition = @model.clipScreenPosition(screenPosition) if clip - + pixelPositionForScreenPosition: (screenPosition) -> targetRow = screenPosition.row targetColumn = screenPosition.column diff --git a/src/repository-status-handler.coffee b/src/repository-status-handler.coffee index d0763fd5a..2fda9a335 100644 --- a/src/repository-status-handler.coffee +++ b/src/repository-status-handler.coffee @@ -1,7 +1,7 @@ Git = require 'git-utils' path = require 'path' -module.exports = (repoPath) -> +module.exports = (repoPath, paths = []) -> repo = Git.open(repoPath) upstream = {} @@ -12,7 +12,8 @@ module.exports = (repoPath) -> if repo? # Statuses in main repo workingDirectoryPath = repo.getWorkingDirectory() - for filePath, status of repo.getStatus() + repoStatus = (if paths.length > 0 then repo.getStatusForPaths(paths) else repo.getStatus()) + for filePath, status of repoStatus statuses[filePath] = status # Statuses in submodules diff --git a/src/text-editor-component.coffee b/src/text-editor-component.coffee index 6a84c8dac..d97d82d04 100644 --- a/src/text-editor-component.coffee +++ b/src/text-editor-component.coffee @@ -434,12 +434,17 @@ class TextEditorComponent getVisibleRowRange: -> @presenter.getVisibleRowRange() - pixelPositionForScreenPosition: (screenPosition, clip) -> + pixelPositionForScreenPosition: (screenPosition, clip=true) -> + screenPosition = Point.fromObject(screenPosition) + screenPosition = @editor.clipScreenPosition(screenPosition) if clip + unless @presenter.isRowVisible(screenPosition.row) @presenter.setScreenRowsToMeasure([screenPosition.row]) + + unless @linesComponent.lineNodeForLineIdAndScreenRow(@presenter.lineIdForScreenRow(screenPosition.row), screenPosition.row)? @updateSyncPreMeasurement() - pixelPosition = @linesYardstick.pixelPositionForScreenPosition(screenPosition, clip) + pixelPosition = @linesYardstick.pixelPositionForScreenPosition(screenPosition) @presenter.clearScreenRowsToMeasure() pixelPosition diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index 1912f4c2e..40ea95514 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -433,7 +433,7 @@ class TextEditorPresenter else screenPosition = decoration.getMarker().getHeadScreenPosition() - pixelPosition = @pixelPositionForScreenPosition(screenPosition, true) + pixelPosition = @pixelPositionForScreenPosition(screenPosition) top = pixelPosition.top + @lineHeight left = pixelPosition.left + @gutterWidth @@ -649,8 +649,10 @@ class TextEditorPresenter updateHorizontalDimensions: -> if @baseCharacterWidth? oldContentWidth = @contentWidth - clip = @model.tokenizedLineForScreenRow(@model.getLongestScreenRow())?.isSoftWrapped() - @contentWidth = @pixelPositionForScreenPosition([@model.getLongestScreenRow(), @model.getMaxScreenLineLength()], clip).left + rightmostPosition = Point(@model.getLongestScreenRow(), @model.getMaxScreenLineLength()) + if @model.tokenizedLineForScreenRow(rightmostPosition.row)?.isSoftWrapped() + rightmostPosition = @model.clipScreenPosition(rightmostPosition) + @contentWidth = @pixelPositionForScreenPosition(rightmostPosition).left @contentWidth += @scrollLeft @contentWidth += 1 unless @model.isSoftWrapped() # account for cursor width @@ -966,9 +968,9 @@ class TextEditorPresenter hasPixelPositionRequirements: -> @lineHeight? and @baseCharacterWidth? - pixelPositionForScreenPosition: (screenPosition, clip=true) -> + pixelPositionForScreenPosition: (screenPosition) -> position = - @linesYardstick.pixelPositionForScreenPosition(screenPosition, clip, true) + @linesYardstick.pixelPositionForScreenPosition(screenPosition) position.top -= @getScrollTop() position.left -= @getScrollLeft() @@ -987,14 +989,14 @@ class TextEditorPresenter lineHeight = @model.getLineHeightInPixels() if screenRange.end.row > screenRange.start.row - top = @linesYardstick.pixelPositionForScreenPosition(screenRange.start, true).top + top = @linesYardstick.pixelPositionForScreenPosition(screenRange.start).top left = 0 height = (screenRange.end.row - screenRange.start.row + 1) * lineHeight width = @getScrollWidth() else - {top, left} = @linesYardstick.pixelPositionForScreenPosition(screenRange.start, false) + {top, left} = @linesYardstick.pixelPositionForScreenPosition(screenRange.start) height = lineHeight - width = @linesYardstick.pixelPositionForScreenPosition(screenRange.end, false).left - left + width = @linesYardstick.pixelPositionForScreenPosition(screenRange.end).left - left {top, left, width, height} @@ -1139,8 +1141,8 @@ class TextEditorPresenter buildHighlightRegions: (screenRange) -> lineHeightInPixels = @lineHeight - startPixelPosition = @pixelPositionForScreenPosition(screenRange.start, false) - endPixelPosition = @pixelPositionForScreenPosition(screenRange.end, false) + startPixelPosition = @pixelPositionForScreenPosition(screenRange.start) + endPixelPosition = @pixelPositionForScreenPosition(screenRange.end) spannedRows = screenRange.end.row - screenRange.start.row + 1 regions = [] @@ -1375,3 +1377,6 @@ class TextEditorPresenter isRowVisible: (row) -> @startRow <= row < @endRow + + lineIdForScreenRow: (screenRow) -> + @model.tokenizedLineForScreenRow(screenRow)?.id diff --git a/src/text-editor.coffee b/src/text-editor.coffee index 1435aef19..91b1409a4 100644 --- a/src/text-editor.coffee +++ b/src/text-editor.coffee @@ -3037,7 +3037,7 @@ class TextEditor extends Model # Essential: Scrolls the editor to the given screen position. # - # * `screenPosition` An object that represents a buffer position. It can be either + # * `screenPosition` An object that represents a screen position. It can be either # an {Object} (`{row, column}`), {Array} (`[row, column]`), or {Point} # * `options` (optional) {Object} # * `center` Center the editor around the position if possible. (default: false)