Structuring buffer change callbacks


#1

I’m working on a (first-time) package that listens for the current editor’s onDidChange() method, however I’m a little stuck on how to structure the registration and disposal of this listener. Currently, I’m using the default toggle() method from the first package creation tutorial:

module.exports = MyPackage =
  subscriptions: null
  active: false
  editor: null
  editorChanges: null

  activate: ->
    […]
    # Register command that toggles this view
    @subscriptions.add atom.commands.add 'atom-workspace', 'mypackage:toggle': => @toggle()

    @editor = atom.workspace.getActiveTextEditor()

  deactivate: ->
    […]

  toggle: ->
    if @active
      @active = false
      @editorChanges.dispose()
    else
      @active = true
      @editorChanges = @editor.onDidChange(->
        console.log @editor.getCursorBufferPosition().column
        )

There are a few issues I’m running into. First, the use of @editor and @editorChanges variables feels redundant, despite the fact that I need to save the return of @editor.onDidChange() so that I can call .dispose() on it later.

Mainly, however, @editor is not recognized in the second to last line when trying to get the cursor position.

How do I structure this package so that I can register and dispose of a callback for the active text editor in a clean manner that allows me to read and manipulate properties of the editor itself inside the callback?


#2

If I properly understood what you want I think something like this should work for you:


module.exports = MyPackage =
  subscriptions: null
  active: false
  editor: null
  editorChanges: null

  activate: ->
    […]
    # Register command that toggles this view
    @subscriptions.add atom.commands.add 'atom-workspace', 'mypackage:toggle': => @toggle()

  deactivate: ->
    […]

  toggle: ->
    if @active
      @active = false

      # We dispose both the workspace and the current editor subscriptions
      # if they exist
      @workspaceSubscription?.dispose()
      @editorSubscription?.dispose()
    else
      @active = true

      # We first listen to the change of the workspace active pane item
      @workspaceSubscription = atom.workspace.onDidChangeActivePaneItem (paneItem) =>
        # And we can handle it if it's a TextEditor
        @handleEditor(paneItem) if paneItem.constructor.name is 'TextEditor'

      # We also want to handle the currently active editor if there's one
      if activeEditor = atom.workspace.getActiveTextEditor()
        @handleEditor(activeEditor) 

  # Here we'll can handle the subscriptions to the editor
  handleEditor: (@editor) =>
    # Since we start handling a different editor we no longer need to listen
    # the changes from the previous one.
    @editorSubscription?.dispose()

    # Then we subscribe to the new editor
    @editorSubscription = @editor.onDidChange =>
      console.log @editor.getCursorBufferPosition().column


#3

Apologies, my post was written while very tired, so it was not the most cohesive. But yes! That looks like exactly what I want. I wasn’t sure how to handle changes to the active pane, but I was kicking that down the road for now.

Edit:

One very minor code edit for anyone referencing this later on:

There is an error when toggling off the package, as @editorSubscription isn’t defined, so it has no .dispose() method. To fix this, change handleEditor: (@editor) => to handleEditor: (@editor) ->.