Skip to content

Commit

Permalink
Merge pull request #91 from mrjoelkemp/taxi
Browse files Browse the repository at this point in the history
Find a driver
  • Loading branch information
mrjoelkemp committed Dec 29, 2014
2 parents ec3ab77 + ea71f3c commit aa17c42
Show file tree
Hide file tree
Showing 1,022 changed files with 721,428 additions and 132 deletions.
4 changes: 3 additions & 1 deletion Context.sublime-menu
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
"children": [
{ "command": "jump_to_dependency", "caption": "Jump to dependency" },
{ "command": "dependents", "caption": "Find dependents" },
{ "command": "dependents", "caption": "Open all dependents", "args": { "modifier": "OPEN_ALL"}}
{ "command": "dependents", "caption": "Open all dependents", "args": { "modifier": "OPEN_ALL"}},
{ "command": "find_driver", "caption": "Find relevant app entry points" },
{ "command": "find_driver", "caption": "Open all relevant app entry points", "args": { "modifier": "OPEN_ALL"}}
]
}
]
9 changes: 9 additions & 0 deletions Default.sublime-commands
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,14 @@
"caption": "Dependents: Open all dependents",
"command": "dependents",
"args": { "modifier": "OPEN_ALL"}
},
{
"caption": "Dependents: Find relevant app entry points",
"command": "find_driver",
},
{
"caption": "Dependents: Open all relevant app entry points",
"command": "find_driver",
"args": { "modifier": "OPEN_ALL"}
}
]
36 changes: 9 additions & 27 deletions Dependents.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@

from .lib.thread_progress import ThreadProgress
from .lib.command_setup import command_setup
from .lib.show_error import show_error

from .lib.show_error import *
from .lib.trim_paths_of_root import trim_paths_of_root
from .lib.track import track as t
from .lib.printer import p

Expand Down Expand Up @@ -44,7 +44,7 @@ def run(self):
"""
total_start_time = time.time()

self.dependents = self.trim_paths(self.get_dependents())
self.dependents = trim_paths_of_root(self.get_dependents(), self.window.root)

if self.view.modifier and self.view.modifier == 'OPEN_ALL':
for dep in self.dependents:
Expand All @@ -57,11 +57,11 @@ def run(self):
sublime.set_timeout(self.show_quick_panel, 10)

tracking_data = {
"etime": time.time() - total_start_time,
'etime': time.time() - total_start_time,
}

if self.view.modifier:
tracking_data["modifier"] = self.view.modifier
tracking_data['modifier'] = self.view.modifier

t('Run_Dependents', tracking_data)

Expand Down Expand Up @@ -97,23 +97,6 @@ def get_dependents(self):

return dependents

def trim_paths(self, files):
"""
Returns the filepaths for each file minus the root and its trailing slash
"""
trimmed = []

for f in files:
if f:
try:
filename = f[f.index(self.window.root) + len(self.window.root):]
except:
p('Didn\'t have root in path', f)
filename = f

trimmed.append(filename)
return trimmed

def show_quick_panel(self):
if not self.dependents:
show_error('Can\'t find any file that depends on this file')
Expand All @@ -128,6 +111,8 @@ def on_done(self, picked):
dependent = self.dependents[picked]
self.open_file(dependent)

# TODO: Consider conslidating with JumpToDependency's implementation
# and moving this to a lib module
def open_file(self, dependent):
path = self.view.path

Expand All @@ -140,15 +125,12 @@ def open_file(self, dependent):

if not os.path.isfile(filename):
t('Missing file', {
"filename": filename
'filename': filename
})
cant_find_file()
return

def open():
self.window.open_file(filename)

sublime.set_timeout(open, 10)

def cant_find_file():
show_error('Can\'t find that file')
sublime.set_timeout(open, 10)
10 changes: 9 additions & 1 deletion Dependents.sublime-settings
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,13 @@
// The location of your sass files
//
// Example: 'public/assets/sass'
"sass_root": ""
"sass_root": "",

// File and folder names to exclude from dependents search
"exclude": [],

// The path to your RequireJS Build Configuration
//
// Example: 'public/assets/js/build.json'
"build_config": ""
}
135 changes: 135 additions & 0 deletions FindDriver.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
import sublime, sublime_plugin
import subprocess
import threading
import os
import re
import time

from .lib.thread_progress import ThreadProgress
from .lib.command_setup import command_setup
from .lib.show_error import *
from .lib.trim_paths_of_root import trim_paths_of_root
from .lib.track import track as t
from .lib.printer import p

from .node_taxicab import find_driver

class FindDriverCommand(sublime_plugin.WindowCommand):
def run(self, modifier=''):
setup_was_successful = command_setup(self)

if not setup_was_successful:
show_error('Dependents: Setup was not successful. Please file an issue', True)
return

self.view.modifier = modifier

thread = FindDriverThread(self.window, self.view)
thread.start();

ThreadProgress(thread, 'Finding relevant entry points', '')

class FindDriverThread(threading.Thread):
def __init__(self, window, view):
self.window = window
self.view = view
threading.Thread.__init__(self)

def run(self):
"""
Finds the driver scripts that depend on the current file and
jumps to that driver file or shows a panel of relevant driver scripts
"""
total_start_time = time.time()

self.drivers = trim_paths_of_root(self.get_drivers(), self.window.root)

if self.view.modifier and self.view.modifier == 'OPEN_ALL':
for driver in self.drivers:
self.open_file(driver)
return

if len(self.drivers) == 1:
self.open_file(self.drivers[0])
else:
sublime.set_timeout(self.show_quick_panel, 10)

tracking_data = {
"etime": time.time() - total_start_time,
}

if self.view.modifier:
tracking_data["modifier"] = self.view.modifier

t('Run_Find_Driver', tracking_data)

def get_drivers(self):
"""
Asks the node tool for the drivers of the current module
"""
root = self.view.path

# In case the user supplied the base path as the root
# TODO: Consider moving this to command_setup
if self.window.root != self.view.path:
root += self.window.root

args = {
'filename': self.view.filename,
'root': root
}

if self.window.config:
args['config'] = self.view.path + self.window.config

if self.window.build_config:
args['build_config'] = self.view.path + self.window.build_config

if self.window.exclude:
args['exclude'] = ','.join(self.window.exclude)

fetch_time = time.time()

drivers = [d for d in find_driver(args) if d]

p('Fetch time:', time.time() - fetch_time)
p(len(drivers), 'drivers found:\n' + '\n'.join(drivers))

return drivers

def show_quick_panel(self):
if not self.drivers:
show_error('Can\'t find any driver that depends on this file')
return

self.window.show_quick_panel(self.drivers, self.on_done)

def on_done(self, picked):
if picked == -1:
return

driver = self.drivers[picked]
self.open_file(driver)

def open_file(self, driver):
# TODO: Duplicative of logic in get_drivers
path = self.view.path

# In case the root is the directory root (path)
if path != self.window.root:
path += self.window.root

# We removed the root originally when populating the dependents list
filename = path + driver

if not os.path.isfile(filename):
t('Missing file', {
"filename": filename
})
cant_find_file()
return

def open():
self.window.open_file(filename)

sublime.set_timeout(open, 10)
36 changes: 4 additions & 32 deletions JumpToDependency.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@
import os
import re
import time
from fnmatch import fnmatch

# TODO: Support Python 2 style imports
from .lib.thread_progress import ThreadProgress
from .lib.show_error import show_error
from .lib.show_error import *
from .lib.command_setup import command_setup

from .lib.find_file_like import find_file_like
from .lib.track import track as t
from .lib.printer import p
from .lib.flatten import flatten

from .node_dependents import alias_lookup

Expand Down Expand Up @@ -193,32 +193,4 @@ def aliasLookup(self, module, config):
return alias_lookup({
'config': self.view.path + config,
'module': module
})

def find_file_like(path):
"""
Traverses the parent directory of path looking for the
first file with a close enough name to the given path.
This is helpful if you don't know the extension of a file
(assuming the filename has a unique extension)
"""
try:
dirname = os.path.dirname(path)
filename = [f for f in os.listdir(dirname) if fnmatch(f, os.path.basename(path) + '.*')]
if len(filename):
return filename[0]
except:
return ''

return ''


def flatten(nested):
"""
Flattens a 2d array into a 1d array
"""
return [item for sublist in nested for item in sublist]

def cant_find_file():
show_error('Can\'t find that file')
})
14 changes: 14 additions & 0 deletions changelogs/2.4.0.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
New Feature: Find relevant app entry points
----

To use:

* Right click on a file to open the context menu
* Click on Dependents -> Find relevant app entry points

Optional:

If you're using RequireJS, you can optionally set the "build_config"
setting to supply the location to your Rjs build configuration file.
* This should have a "modules" section that lists your entry points/bundles

7 changes: 5 additions & 2 deletions changelogs/initial.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
Configuring settings
---

These can be specified by going to
These can be specified by creating a .deprc file with the following
settings in the root directory of your codebase or by going to

`Preferences -> Package Settings -> Dependents -> Settings - User`

Expand All @@ -11,13 +12,15 @@ and adding:
"root": "path/to/my/js",
"config": "path/to/my/requirejs/config.js", # Optional
"sass_root": "path/to/my/sass", # Optional,
"exclude": ['jquery.js', 'plugins/'] # Optional
"exclude": ['jquery.js', 'plugins/'], # Optional
"build_config": "path/to/my/requirejs/build.json" # Optional
}

* "root": the location where your JS files reside
* "config": the location of your RequireJS configuration for AMD codebases
* "sass_root": the location of your SASS files
* "exclude": a list of files and folder names to exclude in the search for dependents
* "build_config": the location of your requirejs build configuration file

* Please modify the values according to your codebase.

Expand Down
1 change: 1 addition & 0 deletions lib/command_setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ def _init(self):
self.window.sass_root = settings['sass_root']
self.window.config = settings['config']
self.window.exclude = settings['exclude']
self.window.build_config = settings['build_config']

if self.window.root == './' or self.window.root == '.':
self.window.root = base_path
Expand Down
20 changes: 20 additions & 0 deletions lib/find_file_like.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import os
from fnmatch import fnmatch

def find_file_like(path):
"""
Traverses the parent directory of path looking for the
first file with a close enough name to the given path.
This is helpful if you don't know the extension of a file
(assuming the filename has a unique extension)
"""
try:
dirname = os.path.dirname(path)
filename = [f for f in os.listdir(dirname) if fnmatch(f, os.path.basename(path) + '.*')]
if len(filename):
return filename[0]
except:
return ''

return ''
5 changes: 5 additions & 0 deletions lib/flatten.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
def flatten(nested):
"""
Flattens a 2d array into a 1d array
"""
return [item for sublist in nested for item in sublist]
Loading

0 comments on commit aa17c42

Please sign in to comment.