How do I know if a command was called from treeview/activepane/command palette?


#1

Hi,

Is there a way to know if a command was called from tree-view context menu or current file?

I’m creating a package that adds context menu to tree-view and also to active pane (current file). So, when I call a command, I need to know the file path, so I do this to active pane

filePath = atom.workspace.getActivePaneItem?().getPath?()

but for the tree-view, I use this

filePath = atom.workspaceView.find('.tree-view .selected').views()?[0][0].getPath?()

I need this different code in tree-view because the user can use the right-click on files (other than that being edited) and I need to call the command for that file. Otherwise, I had to add two different commands, one for the editor and other for the tree-view, and both becomes available on Command Palette :confused:

Thanks in advance


#2

The atom.commands.add callback has an event argument with a currentTarget property that gives the element that triggered the command. Try this and see for yourself:

atom.commands.add '.pane atom-text-editor, .tree-view .selected', 'package:command', myAwesomeCommand

myAwesomeCommand = (e) ->
  console.log e.currentTarget

The li.selected element in the tree view has a getPath method, the atom-text-editor doesn’t have that, but its model does. So you can use this to get the file path:

myAwesomeCommand (e) ->
  target = e.currentTarget
  path = target.getPath?() ? target.getModel?().getPath()

The tree view can, however, have multiple files selected, and this only works for the file that’s actually right clicked, so you should test for a tree view entry, and use tree view’s selectedPaths method:

fs = require('fs')

myAwesomeCommand = (e) ->
  if e.currentTarget.getPath? # this is the tree view entry, you should probably make a better test
    paths = atom.packages.getActivePackage('tree-view')?.mainModule.selectedPaths()
    paths = (path for path in paths when fs.lstatSync(path).isFile()) # filter out directories
  else # this is the pane atom-text-editor
    paths = [e.currentTarget.getModel().getPath()]
  return unless paths? # return if tree view package isn't active
  for path in paths
    # do your stuff for each path

#3

Thanks @olmokramer. It works perfectly :+1:

But, I get a little confused about the syntax difference, mostly because I don’t have much experience with JS/CS. I was using this syntax to register the action (code provided by the Package Generator)

activate: (state) 
  @subscriptions.add atom.commands.add 'atom-workspace', package:command-name': => @myCommand()

myCommand: ->

And coundn’t simply change it to use the (e) event argument, and had to use exactly as you advised. The direct consequence was to move my other commands outside the class. I also get a bit worried about the @subscriptions.add that I lost with this syntax, mostly if this could raise any problem with Atom itself.

I will try to learn a bit more both, JS/CS and Atom API itself to better understand the differences and the consequences, and off course, write better packages :smile:

Thanks again.


#4

If you send me the code, or parts of it, I can take a look at it. What you describe should be possible to achieve. Just guessing here, but you might be able to use this:

class MyClass
  activate: (state) ->
    @subscriptions.add atom.commands.add 'atom-workspace', 'package:command-name', @myCommand

  myCommand: (e) => # notice the fat arrow, it binds this method to the instance of this class (making @methods work)
    # do stuff with e.currentTarget

#5

Yes, it works!

As I was thinking, lack of experience with JS/CS is being a little trick for me :confused:. I really need to understand better some nuances and concepts. But this is good, always learning :wink:

Thanks again.