diff --git a/lib/console.py b/lib/console.py index f4fd9a8..4239ff8 100644 --- a/lib/console.py +++ b/lib/console.py @@ -10,11 +10,7 @@ def __init__(self, console_kernel=None): if self.console_kernel: return for folder in workspace.get_folders(): - fullpath = workspace.get_path( - folder, - 'app/Console/Kernel.php', - True - ) + fullpath = workspace.get_path(folder, 'app/Console/Kernel.php') if not fullpath: continue @@ -40,6 +36,9 @@ def get_command_signature(self, content): return '' def collect_files(self): + ''' + collect command files from $this->load(__DIR__) + ''' files = [] match = re.search( r"""function commands\([^\)]*[^{]+([^}]+)""", @@ -70,6 +69,11 @@ def collect_file_cmds(self, files): return commands def collect_registered_cmds(self): + ''' + collect commands from $command = [ + + ] + ''' commands = {} match = re.search( r"""\$commands\s*=\s*\[([^\]]+)""", diff --git a/lib/finder.py b/lib/finder.py index 1825875..823036c 100644 --- a/lib/finder.py +++ b/lib/finder.py @@ -29,7 +29,7 @@ def get_place(selection): component_place, middleware_place, command_place, - # route_place, + route_place, controller_place, ) diff --git a/lib/middleware.py b/lib/middleware.py index 09eec49..bb10c94 100644 --- a/lib/middleware.py +++ b/lib/middleware.py @@ -43,6 +43,9 @@ def all(self): return middlewares def collect_classnames(self, content): + ''' + collect class aliases + ''' classnames = {} pattern = re.compile(r"use\s+([^\s]+)\s+as+\s+([^;]+)") for match in pattern.findall(content): diff --git a/lib/router.py b/lib/router.py index 8bf5c16..48493ef 100644 --- a/lib/router.py +++ b/lib/router.py @@ -4,26 +4,31 @@ import json from .setting import Setting +routes = {} + class Router: def __init__(self): for folder in workspace.get_folders(): - self.artisan = workspace.get_path( - folder, - 'artisan', - True - ) - if self.artisan: + self.artisan = workspace.get_path(folder, 'artisan') + self.dir = workspace.get_folder_path(folder, 'routes') + if self.dir: return - def all(self): - routes = {} - if not self.artisan: - return routes + def update(self, filepath=None): + ''' + update routes if routes folder's files were changed + ''' + if not self.artisan or not self.dir: + return + + if not workspace.is_changed(self.dir, filepath): + return + workspace.set_unchange(self.dir) php = Setting().get('php_bin') if not php: - return routes + return args = [ php, @@ -36,13 +41,13 @@ def all(self): try: output = subprocess.check_output(args, stderr=subprocess.STDOUT) except subprocess.CalledProcessError: - return routes + return output = output.decode('utf-8') try: route_rows = json.loads(output) except ValueError: - return routes + return for route_row in route_rows: if 'Closure' == route_row['action']: @@ -55,4 +60,6 @@ def all(self): location=action ) + def all(self): + self.update() return routes diff --git a/lib/workspace.py b/lib/workspace.py index eed473d..88b09c5 100644 --- a/lib/workspace.py +++ b/lib/workspace.py @@ -3,12 +3,54 @@ mTimes = {} contents = {} +changes = {} -def get_file_content(folder, filepath=None): - fullpath = folder - if filepath: - fullpath = get_path(folder, filepath, True) +def is_changed(folder_path, file_path=None): + ''' + is the folder's files were changed + :param file_path only check the file in the folder + ''' + + if file_path: + if not file_path.startswith(folder_path): + return False + + mTime = os.path.getmtime(file_path) + return mTimes.get(file_path) != mTime + + if folder_path not in changes: + return True + files = os.listdir(folder_path) + if changes[folder_path] != len(files): + return True + for file in files: + fullpath = os.path.join(folder_path, file) + mTime = os.path.getmtime(fullpath) + if mTimes.get(fullpath) != mTime: + return True + + return False + + +def set_unchange(folder_path): + ''' + set the folder's files is changed + ''' + + files = os.listdir(folder_path) + changes[folder_path] = len(files) + + for file in files: + fullpath = os.path.join(folder_path, file) + mTime = os.path.getmtime(fullpath) + mTimes[fullpath] = mTime + + +def get_file_content(base, file_path=None): + fullpath = base + if file_path: + fullpath = get_path(base, file_path) if not fullpath: return if not os.path.isfile(fullpath): @@ -28,6 +70,9 @@ def get_file_content(folder, filepath=None): def get_recursion_files(folder, ext='.php'): + ''' + get all files including sub-dirs with the extension + ''' files = [] for folder, subfolders, filenames in os.walk(folder): for filename in filenames: @@ -36,31 +81,55 @@ def get_recursion_files(folder, ext='.php'): return files -def get_path(folder, filepath, recursion=False): +def get_folder_path(base, folder_name, recursion=True): + ''' + get real path by folder name + ''' + files = os.listdir(base) + if folder_name in files: + return os.path.join(base, folder_name) + + if not recursion: + return + + for file in files: + folder = os.path.join(base + '/' + file) + if not os.path.isdir(folder): + continue + + fullpath = get_folder_path(folder, folder_name, False) + if fullpath: + return fullpath + + +def get_path(base, file_path, recursion=True): + ''' + get real path by a part of file path + ''' top_dir = None - if '/' in filepath: - top_dir = filepath.split('/')[0] + if '/' in file_path: + top_dir = file_path.split('/')[0] - files = os.listdir(folder) - if not top_dir and filepath in files: - fullpath = os.path.join(folder, filepath) + files = os.listdir(base) + if not top_dir and file_path in files: + fullpath = os.path.join(base, file_path) if os.path.isfile(fullpath): return fullpath return None for file in files: - if os.path.isdir(folder + '/' + file) is False: + if os.path.isdir(base + '/' + file) is False: continue # if not the right dictionary, search the sub dictionaries if top_dir != file: if recursion: - fullpath = get_path(folder + '/' + file, filepath) + fullpath = get_path(base + '/' + file, file_path, False) if fullpath: return fullpath continue - fullpath = os.path.join(folder, filepath) + fullpath = os.path.join(base, file_path) if os.path.isfile(fullpath): return fullpath @@ -70,6 +139,9 @@ def get_folders(): def class_2_file(class_name): + ''' + convert PHP class name to filename + ''' class_name = class_name filename = class_name.replace(',', '').replace('::class', '') filename = filename.replace('\\', '/').strip() + '.php' diff --git a/main.py b/main.py index 7f32271..fc7b488 100644 --- a/main.py +++ b/main.py @@ -19,6 +19,7 @@ from .lib.selection import Selection from .lib.finder import get_place from .lib.setting import Setting +from .lib.router import Router place = None @@ -42,6 +43,9 @@ def on_activated(self, view): view.show(location) place = None + def on_post_save_async(self, view): + Router().update(view.file_name()) + def on_hover(self, view, point, hover_zone): if view.is_popup_visible(): return diff --git a/readme.md b/readme.md index fd63a58..6cb748c 100644 --- a/readme.md +++ b/readme.md @@ -44,6 +44,10 @@ Route::resource('photo', 'HelloController', ['only' => [ ]]); ``` +### Go to Controller from route helper + +![](route.gif) + ### Go to Middleware ![](middleware.gif) diff --git a/route.gif b/route.gif new file mode 100755 index 0000000..28d2e04 Binary files /dev/null and b/route.gif differ diff --git a/tests/test_router.py b/tests/test_router.py index 8b3f393..4af74ac 100644 --- a/tests/test_router.py +++ b/tests/test_router.py @@ -6,14 +6,29 @@ class TestRouter(unittest.ViewTestCase): @patch('subprocess.check_output') + @patch('LaravelGoto.lib.workspace.set_unchange') + @patch('LaravelGoto.lib.workspace.is_changed') @patch('LaravelGoto.lib.workspace.get_path') + @patch('LaravelGoto.lib.workspace.get_folder_path') @patch('LaravelGoto.lib.workspace.get_folders') - def test_all(self, mock_get_folders, mock_get_path, mock_check_output): - mock_get_folders.return_value = [self.get_test_dir()] - mock_get_path.return_value = 'artisan' - mock_check_output.return_value = bytes('[{"name":"admin.index","action":"App\\\\Http\\\\Controllers\\\\AdminController@index","middleware":[]},{"name":null,"action":"Closure","middleware":[]},{"name":null,"action":"Closure","middleware":[]}]', 'utf-8') # noqa: E501 + def test_all( + self, + m_get_folders, + m_get_folder_path, + m_get_path, + m_is_changed, + m_set_unchange, + m_check_output + ): + m_get_folders.return_value = [self.get_test_dir()] + m_get_folder_path.return_value = 'dir' + m_get_path.return_value = 'artisan' + m_is_changed.return_value = True + m_set_unchange.return_value = None + m_check_output.return_value = bytes('[{"name":"admin.index","action":"App\\\\Http\\\\Controllers\\\\AdminController@index","middleware":[]},{"name":null,"action":"Closure","middleware":[]},{"name":null,"action":"Closure","middleware":[]}]', 'utf-8') # noqa: E501 router = Router() + router.update() routes = router.all() self.assertEqual( diff --git a/tests/test_workspace.py b/tests/test_workspace.py index 7243e89..bf42575 100644 --- a/tests/test_workspace.py +++ b/tests/test_workspace.py @@ -12,18 +12,15 @@ def test_get_file_content(self): content.__contains__('class Kernel extends HttpKernel') ) - content = workspace.get_file_content(__file__) - self.assertTrue(content.__contains__('TestWorkspace')) - def test_get_path(self): folder = os.path.dirname(os.path.abspath(__file__)) - fullpapth = workspace.get_path(folder, 'app/Http/Kernel.php', True) + fullpapth = workspace.get_path(folder, 'app/Http/Kernel.php') self.assertTrue(fullpapth.__contains__('app/Http/Kernel.php')) - fullpapth = workspace.get_path(folder, 'unittest.py', True) + fullpapth = workspace.get_path(folder, 'unittest.py') self.assertTrue(fullpapth.__contains__('unittest.py')) - fullpapth = workspace.get_path(folder, 'sample.php', True) + fullpapth = workspace.get_path(folder, 'sample.php') self.assertTrue(fullpapth.__contains__('sample.php')) def test_get_recursion_files(self): @@ -38,3 +35,24 @@ def test_get_recursion_files(self): def test_class_2_file(self): filename = workspace.class_2_file("\\App\\NS\\SayGoodbye::class,") self.assertEqual(filename, 'app/NS/SayGoodbye.php') + + def test_get_folder_path(self): + base = os.path.dirname(os.path.abspath(__file__)) + + path = workspace.get_folder_path(base, 'fixtures') + self.assertTrue(path.endswith('fixtures'), path) + + path = workspace.get_folder_path(base, 'config') + self.assertTrue(path.endswith('config'), path) + + path = workspace.get_folder_path(base, 'Http') + self.assertFalse(path) + + def test_changed(self): + base = os.path.dirname(os.path.abspath(__file__)) + self.assertTrue(workspace.is_changed(base)) + self.assertTrue(workspace.is_changed(base, __file__)) + self.assertFalse(workspace.is_changed(base, '/aaa/bbb')) + workspace.set_unchange(base) + self.assertFalse(workspace.is_changed(base), 'post') + self.assertFalse(workspace.is_changed(base, __file__))