示例#1
0
  // Keep a {TextEditor}'s configuration in sync with Atom's settings.
  //
  // * `editor` The editor whose configuration will be maintained.
  //
  // Returns a {Disposable} that can be used to stop updating the editor's
  // configuration.
  maintainConfig (editor) {
    if (this.editorsWithMaintainedConfig.has(editor)) {
      return new Disposable(noop)
    }
    this.editorsWithMaintainedConfig.add(editor)

    this.updateAndMonitorEditorSettings(editor)
    const languageChangeSubscription = editor.buffer.onDidChangeLanguageMode((newLanguageMode, oldLanguageMode) => {
      this.updateAndMonitorEditorSettings(editor, oldLanguageMode)
    })
    this.subscriptions.add(languageChangeSubscription)

    const updateTabTypes = () => {
      const configOptions = {scope: editor.getRootScopeDescriptor()}
      editor.setSoftTabs(shouldEditorUseSoftTabs(
        editor,
        this.config.get('editor.tabType', configOptions),
        this.config.get('editor.softTabs', configOptions)
      ))
    }

    updateTabTypes()
    const tokenizeSubscription = editor.onDidTokenize(updateTabTypes)
    this.subscriptions.add(tokenizeSubscription)

    return new Disposable(() => {
      this.editorsWithMaintainedConfig.delete(editor)
      tokenizeSubscription.dispose()
      languageChangeSubscription.dispose()
      this.subscriptions.remove(languageChangeSubscription)
      this.subscriptions.remove(tokenizeSubscription)
    })
  }
示例#2
0
  constructor (path, options = {}) {
    this.id = nextId++
    this.emitter = new Emitter()
    this.subscriptions = new CompositeDisposable()
    this.repo = GitUtils.open(path)
    if (this.repo == null) {
      throw new Error(`No Git repository found searching path: ${path}`)
    }

    this.statusRefreshCount = 0
    this.statuses = {}
    this.upstream = {ahead: 0, behind: 0}
    for (let submodulePath in this.repo.submodules) {
      const submoduleRepo = this.repo.submodules[submodulePath]
      submoduleRepo.upstream = {ahead: 0, behind: 0}
    }

    this.project = options.project
    this.config = options.config

    if (options.refreshOnWindowFocus || options.refreshOnWindowFocus == null) {
      const onWindowFocus = () => {
        this.refreshIndex()
        this.refreshStatus()
      }

      window.addEventListener('focus', onWindowFocus)
      this.subscriptions.add(new Disposable(() => window.removeEventListener('focus', onWindowFocus)))
    }

    if (this.project != null) {
      this.project.getBuffers().forEach(buffer => this.subscribeToBuffer(buffer))
      this.subscriptions.add(this.project.onDidAddBuffer(buffer => this.subscribeToBuffer(buffer)))
    }
  }
示例#3
0
  loadUserStylesheet () {
    this.unwatchUserStylesheet()

    const userStylesheetPath = this.styleManager.getUserStyleSheetPath()
    if (!fs.isFileSync(userStylesheetPath)) { return }

    try {
      this.userStylesheetFile = new File(userStylesheetPath)
      this.userStylesheetSubscriptions = new CompositeDisposable()
      const reloadStylesheet = () => this.loadUserStylesheet()
      this.userStylesheetSubscriptions.add(this.userStylesheetFile.onDidChange(reloadStylesheet))
      this.userStylesheetSubscriptions.add(this.userStylesheetFile.onDidRename(reloadStylesheet))
      this.userStylesheetSubscriptions.add(this.userStylesheetFile.onDidDelete(reloadStylesheet))
    } catch (error) {
      const message = `\
Unable to watch path: \`${path.basename(userStylesheetPath)}\`. Make sure
you have permissions to \`${userStylesheetPath}\`.

On linux there are currently problems with watch sizes. See
[this document][watches] for more info.
[watches]:https://github.com/atom/atom/blob/master/docs/build-instructions/linux.md#typeerror-unable-to-watch-path\
`
      this.notificationManager.addError(message, {dismissable: true})
    }

    let userStylesheetContents
    try {
      userStylesheetContents = this.loadStylesheet(userStylesheetPath, true)
    } catch (error) {
      return
    }

    this.userStyleSheetDisposable = this.styleManager.addStyleSheet(userStylesheetContents, {sourcePath: userStylesheetPath, priority: 2})
  }
示例#4
0
  constructor (_path, options = {}) {
    Git.enableThreadSafety()

    this.emitter = new Emitter()
    this.subscriptions = new CompositeDisposable()
    this.pathStatusCache = {}
    this.path = null

    // NB: These needs to happen before the following .openRepository call.
    this.openedPath = _path
    this._openExactPath = options.openExactPath || false

    this.repoPromise = this.openRepository()
    this.isCaseInsensitive = fs.isCaseInsensitive()
    this.upstream = {}
    this.submodules = {}

    this._refreshingPromise = Promise.resolve()

    let {refreshOnWindowFocus = true} = options
    if (refreshOnWindowFocus) {
      const onWindowFocus = () => this.refreshStatus()
      window.addEventListener('focus', onWindowFocus)
      this.subscriptions.add(new Disposable(() => window.removeEventListener('focus', onWindowFocus)))
    }

    const {project, subscribeToBuffers} = options
    this.project = project
    if (this.project && subscribeToBuffers) {
      this.project.getBuffers().forEach(buffer => this.subscribeToBuffer(buffer))
      this.subscriptions.add(this.project.onDidAddBuffer(buffer => this.subscribeToBuffer(buffer)))
    }
  }
示例#5
0
  // Public: Add one or more command listeners associated with a selector.
  //
  // ## Arguments: Registering One Command
  //
  // * `target` A {String} containing a CSS selector or a DOM element. If you
  //   pass a selector, the command will be globally associated with all matching
  //   elements. The `,` combinator is not currently supported. If you pass a
  //   DOM element, the command will be associated with just that element.
  // * `commandName` A {String} containing the name of a command you want to
  //   handle such as `user:insert-date`.
  // * `listener` A listener which handles the event.  Either a {Function} to
  //   call when the given command is invoked on an element matching the
  //   selector, or an {Object} with a `didDispatch` property which is such a
  //   function.
  //
  //   The function (`listener` itself if it is a function, or the `didDispatch`
  //   method if `listener` is an object) will be called with `this` referencing
  //   the matching DOM node and the following argument:
  //     * `event`: A standard DOM event instance. Call `stopPropagation` or
  //       `stopImmediatePropagation` to terminate bubbling early.
  //
  //   Additionally, `listener` may have additional properties which are returned
  //   to those who query using `atom.commands.findCommands`, as well as several
  //   meaningful metadata properties:
  //     * `displayName`: Overrides any generated `displayName` that would
  //       otherwise be generated from the event name.
  //     * `description`: Used by consumers to display detailed information about
  //       the command.
  //     * `hiddenInCommandPalette`: If `true`, this command will not appear in
  //       the bundled command palette by default, but can still be shown with.
  //       the `Command Palette: Show Hidden Commands` command. This is a good
  //       option when you need to register large numbers of commands that don't
  //       make sense to be executed from the command palette. Please use this
  //       option conservatively, as it could reduce the discoverability of your
  //       package's commands.
  //
  // ## Arguments: Registering Multiple Commands
  //
  // * `target` A {String} containing a CSS selector or a DOM element. If you
  //   pass a selector, the commands will be globally associated with all
  //   matching elements. The `,` combinator is not currently supported.
  //   If you pass a DOM element, the command will be associated with just that
  //   element.
  // * `commands` An {Object} mapping command names like `user:insert-date` to
  //   listener {Function}s.
  //
  // Returns a {Disposable} on which `.dispose()` can be called to remove the
  // added command handler(s).
  add (target, commandName, listener, throwOnInvalidSelector = true) {
    if (typeof commandName === 'object') {
      const commands = commandName
      throwOnInvalidSelector = listener
      const disposable = new CompositeDisposable()
      for (commandName in commands) {
        listener = commands[commandName]
        disposable.add(this.add(target, commandName, listener, throwOnInvalidSelector))
      }
      return disposable
    }

    if (listener == null) {
      throw new Error('Cannot register a command with a null listener.')
    }

    // type Listener = ((e: CustomEvent) => void) | {
    //   displayName?: string,
    //   description?: string,
    //   didDispatch(e: CustomEvent): void,
    // }
    if ((typeof listener !== 'function') && (typeof listener.didDispatch !== 'function')) {
      throw new Error('Listener must be a callback function or an object with a didDispatch method.')
    }

    if (typeof target === 'string') {
      if (throwOnInvalidSelector) {
        validateSelector(target)
      }
      return this.addSelectorBasedListener(target, commandName, listener)
    } else {
      return this.addInlineListener(target, commandName, listener)
    }
  }
示例#6
0
 return new Disposable(() => {
   this.editorsWithMaintainedConfig.delete(editor)
   tokenizeSubscription.dispose()
   languageChangeSubscription.dispose()
   this.subscriptions.remove(languageChangeSubscription)
   this.subscriptions.remove(tokenizeSubscription)
 })
示例#7
0
  constructor(
    socket: Socket,
    onStatusCallback: StatusCallback,
    onNotificationCallback: NotificationCallback,
    isDummyConnection: boolean,
  ) {
    const dbgpSocket = new DbgpSocket(socket);
    this._socket = dbgpSocket;
    this._dataCache = new DataCache(dbgpSocket);
    this._id = connectionCount++;
    this._status = ConnectionStatus.Starting;
    this._isDummyConnection = isDummyConnection;
    this._isDummyViewable = false;
    this._disposables = new CompositeDisposable();
    this._breakCount = 0;

    if (onStatusCallback != null) {
      this._disposables.add(
        this.onStatus((status, ...args) =>
          onStatusCallback(this, status, ...args),
        ),
      );
    }
    if (onNotificationCallback != null) {
      this._disposables.add(
        this.onNotification((notifyName, notify) =>
          onNotificationCallback(this, notifyName, notify),
        ),
      );
    }
    this._stopReason = null;
    this._stopBreakpointLocation = null;
  }
示例#8
0
 return new Disposable(() => {
   destroySubscription.dispose()
   pathChangeSubscription.dispose()
   this.subscriptions.remove(pathChangeSubscription)
   this.subscriptions.remove(destroySubscription)
   this.grammarScoresByBuffer.delete(buffer)
   this.languageOverridesByBufferId.delete(buffer.id)
 })
示例#9
0
 return new Disposable(() => {
   this.editorsWithMaintainedConfig.delete(editor)
   editor.setScopedSettingsDelegate(null)
   tokenizeSubscription.dispose()
   grammarChangeSubscription.dispose()
   this.subscriptions.remove(grammarChangeSubscription)
   this.subscriptions.remove(tokenizeSubscription)
 })
示例#10
0
  initialize (model, {views}) {
    this.model = model
    this.views = views
    if (this.views == null) {
      throw new Error('Must pass a views parameter when initializing PanelContainerElements')
    }

    this.subscriptions.add(this.model.onDidAddPanel(this.panelAdded.bind(this)))
    this.subscriptions.add(this.model.onDidDestroy(this.destroyed.bind(this)))
    this.classList.add(this.model.getLocation())
    return this
  }
示例#11
0
  initialize (model, viewRegistry) {
    this.model = model
    this.viewRegistry = viewRegistry

    this.subscriptions.add(this.model.onDidAddPanel(this.panelAdded.bind(this)))
    this.subscriptions.add(this.model.onDidDestroy(this.destroyed.bind(this)))
    this.classList.add(this.model.getLocation())

    // Add the dock.
    if (this.model.dock != null) {
      this.appendChild(this.model.dock.getElement())
    }

    return this
  }
示例#12
0
  panelAdded ({panel, index}) {
    const panelElement = panel.getElement()
    panelElement.classList.add(this.model.getLocation())
    if (this.model.isModal()) {
      panelElement.classList.add('overlay', 'from-top')
    } else {
      panelElement.classList.add('tool-panel', `panel-${this.model.getLocation()}`)
    }

    if (index >= this.childNodes.length) {
      this.appendChild(panelElement)
    } else {
      const referenceItem = this.childNodes[index]
      this.insertBefore(panelElement, referenceItem)
    }

    if (this.model.isModal()) {
      this.hideAllPanelsExcept(panel)
      this.subscriptions.add(panel.onDidChangeVisible(visible => {
        if (visible) { this.hideAllPanelsExcept(panel) }
      }))

      if (panel.autoFocus) {
        const focusOptions = {
          // focus-trap will attempt to give focus to the first tabbable element
          // on activation. If there aren't any tabbable elements,
          // give focus to the panel element itself
          fallbackFocus: panelElement,
          // closing is handled by core Atom commands and this already deactivates
          // on visibility changes
          escapeDeactivates: false
        }

        if (panel.autoFocus !== true) {
          focusOptions.initialFocus = panel.autoFocus
        }
        const modalFocusTrap = focusTrap(panelElement, focusOptions)

        this.subscriptions.add(panel.onDidChangeVisible(visible => {
          if (visible) {
            modalFocusTrap.activate()
          } else {
            modalFocusTrap.deactivate()
          }
        }))
      }
    }
  }
示例#13
0
文件: pane.js 项目: Jahhein/atom
  // Public: Add the given item to the pane.
  //
  // * `item` The item to add. It can be a model with an associated view or a
  //   view.
  // * `options` (optional) {Object}
  //   * `index` (optional) {Number} indicating the index at which to add the item.
  //     If omitted, the item is added after the current active item.
  //   * `pending` (optional) {Boolean} indicating that the item should be
  //     added in a pending state. Existing pending items in a pane are replaced with
  //     new pending items when they are opened.
  //
  // Returns the added item.
  addItem (item, options = {}) {
    // Backward compat with old API:
    //   addItem(item, index=@getActiveItemIndex() + 1)
    if (typeof options === 'number') {
      Grim.deprecate(`Pane::addItem(item, ${options}) is deprecated in favor of Pane::addItem(item, {index: ${options}})`)
      options = {index: options}
    }

    const index = options.index != null ? options.index : this.getActiveItemIndex() + 1
    const moved = options.moved != null ? options.moved : false
    const pending = options.pending != null ? options.pending : false

    if (!item || typeof item !== 'object') {
      throw new Error(`Pane items must be objects. Attempted to add item ${item}.`)
    }

    if (typeof item.isDestroyed === 'function' && item.isDestroyed()) {
      throw new Error(`Adding a pane item with URI '${typeof item.getURI === 'function' && item.getURI()}' that has already been destroyed`)
    }

    if (this.items.includes(item)) return

    if (typeof item.onDidDestroy === 'function') {
      const itemSubscriptions = new CompositeDisposable()
      itemSubscriptions.add(item.onDidDestroy(() => this.removeItem(item, false)))
      if (typeof item.onDidTerminatePendingState === 'function') {
        itemSubscriptions.add(item.onDidTerminatePendingState(() => {
          if (this.getPendingItem() === item) this.clearPendingItem()
        }))
      }
      this.subscriptionsPerItem.set(item, itemSubscriptions)
    }

    this.items.splice(index, 0, item)
    const lastPendingItem = this.getPendingItem()
    const replacingPendingItem = lastPendingItem != null && !moved
    if (replacingPendingItem) this.pendingItem = null
    if (pending) this.setPendingItem(item)

    this.emitter.emit('did-add-item', {item, index, moved})
    if (!moved) {
      if (this.container) this.container.didAddPaneItem(item, this, index)
    }

    if (replacingPendingItem) this.destroyItem(lastPendingItem)
    if (!this.getActiveItem()) this.setActiveItem(item)
    return item
  }
示例#14
0
  async launch (options) {
    if (!this.configFilePromise) {
      this.configFilePromise = this.configFile.watch()
      this.disposable.add(await this.configFilePromise)
      this.config.onDidChange('core.titleBar', this.promptForRestart.bind(this))
    }

    const optionsForWindowsToOpen = []

    let shouldReopenPreviousWindows = false

    if (options.test || options.benchmark || options.benchmarkTest) {
      optionsForWindowsToOpen.push(options)
    } else if ((options.pathsToOpen && options.pathsToOpen.length > 0) ||
               (options.urlsToOpen && options.urlsToOpen.length > 0)) {
      optionsForWindowsToOpen.push(options)
      shouldReopenPreviousWindows = this.config.get('core.restorePreviousWindowsOnStart') === 'always'
    } else {
      shouldReopenPreviousWindows = this.config.get('core.restorePreviousWindowsOnStart') !== 'no'
    }

    if (shouldReopenPreviousWindows) {
      for (const previousOptions of await this.loadPreviousWindowOptions()) {
        optionsForWindowsToOpen.push(Object.assign({}, options, previousOptions))
      }
    }

    if (optionsForWindowsToOpen.length === 0) {
      optionsForWindowsToOpen.push(options)
    }

    return optionsForWindowsToOpen.map(options => this.openWithOptions(options))
  }
 dispose () {
   this.subscriptions.dispose()
   this.disposeProjectMenu()
   if (this.reopenProjectListView != null) {
     this.reopenProjectListView.dispose()
   }
 }
示例#16
0
  // Private: Initialize a native watcher on a path.
  //
  // Events will not be produced until {start()} is called.
  constructor (normalizedPath) {
    this.normalizedPath = normalizedPath
    this.emitter = new Emitter()
    this.subs = new CompositeDisposable()

    this.backend = null
    this.state = WATCHER_STATE.STOPPED

    this.onEvents = this.onEvents.bind(this)
    this.onError = this.onError.bind(this)

    this.subs.add(atom.config.onDidChange('core.fileSystemWatcher', async () => {
      if (this.state === WATCHER_STATE.STARTING) {
        // Wait for this watcher to finish starting.
        await new Promise(resolve => {
          const sub = this.onDidStart(() => {
            sub.dispose()
            resolve()
          })
        })
      }

      // Re-read the config setting in case it's changed again while we were waiting for the watcher
      // to start.
      const Backend = this.getCurrentBackend()
      if (this.state === WATCHER_STATE.RUNNING && !(this.backend instanceof Backend)) {
        await this.stop()
        await this.start()
      }
    }))
  }
 _sendArgumentsToPythonBackend(
   child: child_process$ChildProcess,
   args: LaunchAttachArgsType
 ): void {
   const ARGUMENT_INPUT_FD = 3;
   /* $FlowFixMe - update Flow defs for ChildProcess */
   const argumentsStream = child.stdio[ARGUMENT_INPUT_FD];
   // Make sure the bidirectional communication channel is set up before
   // sending data.
   argumentsStream.write('init\n');
   this._subscriptions.add(new DisposableSubscription(
     observeStream(argumentsStream).first().subscribe(
       text => {
         if (text.startsWith('ready')) {
           const args_in_json = JSON.stringify(args);
           logInfo(`Sending ${args_in_json} to child_process`);
           argumentsStream.write(`${args_in_json}\n`);
         } else {
           logError(`Get unknown initial data: ${text}.`);
           child.kill();
         }
       },
       error => logError(`argumentsStream error: ${JSON.stringify(error)}`)
   )));
 }
示例#18
0
 destroy () {
   this.alive = false
   for (let pane of this.getRoot().getPanes()) { pane.destroy() }
   this.cancelStoppedChangingActivePaneItemTimeout()
   this.subscriptions.dispose()
   this.emitter.dispose()
 }
示例#19
0
文件: project.js 项目: brettle/atom
 addBuffer (buffer, options = {}) {
   this.buffers.push(buffer)
   this.subscriptions.add(this.grammarRegistry.maintainLanguageMode(buffer))
   this.subscribeToBuffer(buffer)
   this.emitter.emit('did-add-buffer', buffer)
   return buffer
 }
示例#20
0
  // Extended: set a {TextBuffer}'s language mode based on its path and content,
  // and continue to update its language mode as grammars are added or updated, or
  // the buffer's file path changes.
  //
  // * `buffer` The {TextBuffer} whose language mode will be maintained.
  //
  // Returns a {Disposable} that can be used to stop updating the buffer's
  // language mode.
  maintainLanguageMode (buffer) {
    this.grammarScoresByBuffer.set(buffer, null)

    const languageOverride = this.languageOverridesByBufferId.get(buffer.id)
    if (languageOverride) {
      this.assignLanguageMode(buffer, languageOverride)
    } else {
      this.autoAssignLanguageMode(buffer)
    }

    const pathChangeSubscription = buffer.onDidChangePath(() => {
      this.grammarScoresByBuffer.delete(buffer)
      if (!this.languageOverridesByBufferId.has(buffer.id)) {
        this.autoAssignLanguageMode(buffer)
      }
    })

    const destroySubscription = buffer.onDidDestroy(() => {
      this.grammarScoresByBuffer.delete(buffer)
      this.languageOverridesByBufferId.delete(buffer.id)
      this.subscriptions.remove(destroySubscription)
      this.subscriptions.remove(pathChangeSubscription)
    })

    this.subscriptions.add(pathChangeSubscription, destroySubscription)

    return new Disposable(() => {
      destroySubscription.dispose()
      pathChangeSubscription.dispose()
      this.subscriptions.remove(pathChangeSubscription)
      this.subscriptions.remove(destroySubscription)
      this.grammarScoresByBuffer.delete(buffer)
      this.languageOverridesByBufferId.delete(buffer.id)
    })
  }
示例#21
0
 subs.add(term.onExit(function () {
   if (that.subs) {
     that.subs.remove(subs);
   }
   subs.dispose();
   delete that.terms[termID];
 }));
示例#22
0
  // Set a {TextEditor}'s grammar based on its path and content, and continue
  // to update its grammar as grammars are added or updated, or the editor's
  // file path changes.
  //
  // * `editor` The editor whose grammar will be maintained.
  //
  // Returns a {Disposable} that can be used to stop updating the editor's
  // grammar.
  maintainGrammar (editor) {
    if (this.editorsWithMaintainedGrammar.has(editor)) {
      return new Disposable(noop)
    }

    this.editorsWithMaintainedGrammar.add(editor)

    const buffer = editor.getBuffer()
    for (let existingEditor of this.editorsWithMaintainedGrammar) {
      if (existingEditor.getBuffer() === buffer) {
        const existingOverride = this.editorGrammarOverrides[existingEditor.id]
        if (existingOverride) {
          this.editorGrammarOverrides[editor.id] = existingOverride
        }
        break
      }
    }

    this.selectGrammarForEditor(editor)

    const pathChangeSubscription = editor.onDidChangePath(() => {
      this.editorGrammarScores.delete(editor)
      this.selectGrammarForEditor(editor)
    })

    this.subscriptions.add(pathChangeSubscription)

    return new Disposable(() => {
      delete this.editorGrammarOverrides[editor.id]
      this.editorsWithMaintainedGrammar.delete(editor)
      this.subscriptions.remove(pathChangeSubscription)
      pathChangeSubscription.dispose()
    })
  }
示例#23
0
 async destroy () {
   const windowsClosePromises = this.getAllWindows().map(window => {
     window.close()
     return window.closedPromise
   })
   await Promise.all(windowsClosePromises)
   this.disposable.dispose()
 }
示例#24
0
 subs.add(term.onExit(function () {
   Socket.send_delete_term({id: termID});
   if (that.subs) {
     that.subs.remove(subs);
   }
   subs.dispose();
   delete that.terms[termID];
 }));
示例#25
0
文件: dock.js 项目: SnehPandya18/atom
 destroy () {
   this.subscriptions.dispose()
   this.paneContainer.destroy()
   window.removeEventListener('mousemove', this.handleMouseMove)
   window.removeEventListener('mouseup', this.handleMouseUp)
   window.removeEventListener('drag', this.handleDrag)
   window.removeEventListener('dragend', this.handleDragEnd)
 }
示例#26
0
  // Extended: Unsubscribe all subscribers from filesystem events. Native resources will be released asynchronously,
  // but this watcher will stop broadcasting events immediately.
  dispose () {
    for (const sub of this.changeCallbacks.values()) {
      sub.dispose()
    }

    this.emitter.dispose()
    this.subs.dispose()
  }
示例#27
0
  // Public: Destroy this {GitRepositoryAsync} object.
  //
  // This destroys any tasks and subscriptions and releases the underlying
  // libgit2 repository handle. This method is idempotent.
  destroy () {
    this.repo.destroy()

    if (this.subscriptions) {
      this.subscriptions.dispose()
      this.subscriptions = null
    }
  }
示例#28
0
 // Extended: Create a new text editor.
 //
 // Returns a {TextEditor}.
 buildTextEditor (params) {
   const editor = this.textEditorRegistry.build(params)
   const subscriptions = new CompositeDisposable(
     this.textEditorRegistry.maintainGrammar(editor),
     this.textEditorRegistry.maintainConfig(editor)
   )
   editor.onDidDestroy(() => { subscriptions.dispose() })
   return editor
 }
示例#29
0
  activate() {
    this.createCollection()

    this.disposables = new CompositeDisposable
    this.disposables.add(atom.commands.add('atom-workspace', {
      'todo-show:toggle': (event) => this.show(undefined, event),
      'todo-show:find-in-workspace': () => this.show('workspace'),
      'todo-show:find-in-project': () => this.show('project'),
      'todo-show:find-in-open-files': () => this.show('open'),
      'todo-show:find-in-active-file': () => this.show('active')
    }))

    this.disposables.add(atom.workspace.addOpener(uri => {
      if (uri === this.URI) {
        return this.deserializeTodoView()
      }
    }))
  }
 initialize (model, {views}) {
   this.model = model
   this.views = views
   if (this.views == null) {
     throw new Error('Must pass a views parameter when initializing PaneContainerElements')
   }
   this.subscriptions.add(this.model.observeRoot(this.rootChanged.bind(this)))
   return this
 }