├── .gitignore ├── Base File.sublime-settings ├── Default (OSX).sublime-keymap ├── Default (Linux).sublime-keymap ├── Default (Windows).sublime-keymap ├── Default.sublime-commands ├── PhpNamespaceCopy.py ├── README.md ├── test_namespaces.py ├── namespaces.py └── Main.sublime-menu /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc -------------------------------------------------------------------------------- /Base File.sublime-settings: -------------------------------------------------------------------------------- 1 | { 2 | "php_namespace.stop_folders": [ 3 | "src", 4 | "workspace" 5 | ] 6 | } -------------------------------------------------------------------------------- /Default (OSX).sublime-keymap: -------------------------------------------------------------------------------- 1 | [ 2 | { "keys": ["alt+c"], "command": "php_namespace_copy" }, 3 | { "keys": ["alt+u"], "command": "php_namespace_insert_use" }, 4 | { "keys": ["alt+i"], "command": "php_namespace_insert_namespace" } 5 | ] -------------------------------------------------------------------------------- /Default (Linux).sublime-keymap: -------------------------------------------------------------------------------- 1 | [ 2 | { "keys": ["alt+c"], "command": "php_namespace_copy" }, 3 | { "keys": ["alt+u"], "command": "php_namespace_insert_use" }, 4 | { "keys": ["alt+i"], "command": "php_namespace_insert_namespace" } 5 | ] -------------------------------------------------------------------------------- /Default (Windows).sublime-keymap: -------------------------------------------------------------------------------- 1 | [ 2 | { "keys": ["alt+c"], "command": "php_namespace_copy" }, 3 | { "keys": ["alt+u"], "command": "php_namespace_insert_use" }, 4 | { "keys": ["alt+i"], "command": "php_namespace_insert_namespace" } 5 | ] -------------------------------------------------------------------------------- /Default.sublime-commands: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "caption": "PHP Namespace: Insert", 4 | "command": "php_namespace_insert_namespace" 5 | }, 6 | { 7 | "caption": "PHP Namespace: Copy", 8 | "command": "php_namespace_copy" 9 | }, 10 | { 11 | "caption": "PHP Namespace: Insert Use", 12 | "command": "php_namespace_insert_use" 13 | } 14 | ] -------------------------------------------------------------------------------- /PhpNamespaceCopy.py: -------------------------------------------------------------------------------- 1 | import sublime, sublime_plugin, os 2 | 3 | from namespaces import * 4 | 5 | global currentView 6 | 7 | class PhpNamespaceCopyCommand(sublime_plugin.WindowCommand): 8 | def run(self): 9 | if is_php_file(self.window.active_view()): 10 | sublime.set_clipboard(get_namespace(self.window)) 11 | close_overlay(self.window, currentView) 12 | 13 | class PhpNamespaceInsertUseCommand(sublime_plugin.WindowCommand): 14 | def run(self): 15 | if is_php_file(self.window.active_view()): 16 | namespace = get_namespace(self.window) 17 | close_overlay(self.window, currentView) 18 | if is_php_file(self.window.active_view()): 19 | insert_use_statement(self.window.active_view(), namespace) 20 | 21 | class PhpNamespaceInsertNamespaceCommand(sublime_plugin.TextCommand): 22 | def run(self, edit): 23 | if is_php_file(self.view): 24 | insert_namespace_statement(self.view, edit, build_namespace(self.view)) 25 | 26 | class PhpNamespaceEventListener(sublime_plugin.EventListener): 27 | def on_activated(self, view): 28 | global currentView 29 | if None != view.window(): 30 | if is_file_opened(view.window(), view): 31 | currentView = view 32 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SublimeText PHP Namespace # 2 | 3 | PHP Namespace is a **3 in 1** package to use **PHP Namespaces** with **SublimeText 2 and 3**. 4 | 5 | ## Installation ## 6 | 7 | ### With Package Control ### 8 | 9 | Look for the package named `PhpNamespace`. 10 | 11 | ### With Git ### 12 | 13 | Move to your SublimeText Packages folder and clone it : 14 | 15 | ``` 16 | git clone https://github.com/gl3n/sublime-php-namespace PhpNamespace 17 | ``` 18 | 19 | If you have **SublimeText 3**, use ``ST3`` branch : 20 | 21 | ``` 22 | git checkout ST3 23 | ``` 24 | 25 | ## Features ## 26 | 27 | ### 1. php_namespace_copy ### 28 | 29 | It builds the current file namespace and copies it into the clipboard. 30 | 31 | Default shortcut : `alt+c` 32 | 33 | > Note: It can be used via **Goto File Overlay**. 34 | 35 | ### 2. php_namespace_insert_use ### 36 | 37 | It builds the `use <...>;` statement of the current file namespace and inserts it into the last active file. 38 | 39 | Default shortcut : `alt+u` 40 | 41 | > Note: It can be used via **Goto File Overlay**. 42 | 43 | ### 3. php_namespace_insert_namespace ### 44 | 45 | It builds and inserts (or replaces) the `namespace <...>;` statement of the current file. 46 | 47 | Default shortcut : `alt+i` 48 | 49 | ## Settings ## 50 | 51 | ``` 52 | { 53 | "php_namespace.stop_folders": [ 54 | "src", 55 | "workspace" 56 | ] 57 | } 58 | ``` 59 | 60 | The `php_namespace.stop_folders` setting is used for `php_namespace_insert_namespace` command. It defines the folders where the namespace building has to stop. 61 | -------------------------------------------------------------------------------- /test_namespaces.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | from unittest.mock import Mock 3 | from namespaces import * 4 | 5 | class namespaceTestCase(unittest.TestCase): 6 | def testIs_php_fileTrue(self): 7 | view = Mock() 8 | view.file_name = Mock(return_value='test.php') 9 | assert is_php_file(view) == True 10 | def testIs_php_fileFalse(self): 11 | view = Mock() 12 | view.file_name = Mock(return_value='test'+os.sep+'test.html') 13 | assert is_php_file(view) == False 14 | def testGet_namespaceClass(self): 15 | view = Mock() 16 | view.find = Mock() 17 | view.substr = Mock(side_effect=['namespace test1\\test2;','class test3']) 18 | window = Mock() 19 | window.active_view = Mock(return_value=view) 20 | assert get_namespace(window) == 'test1\\test2\\test3' 21 | def testGet_namespaceInterface(self): 22 | view = Mock() 23 | view.find = Mock() 24 | view.substr = Mock(side_effect=['namespace test1\\test2\\test3;','interface test4']) 25 | window = Mock() 26 | window.active_view = Mock(return_value=view) 27 | assert get_namespace(window) == 'test1\\test2\\test3\\test4' 28 | def testBuild_namespace(self): 29 | file_path = ['folder1','folder2','src','folder3','folder4','test.php'] 30 | settings = Mock() 31 | settings.get = Mock(return_value=['src','tests']) 32 | view = Mock() 33 | view.settings = Mock(return_value=settings) 34 | view.file_name = Mock(return_value=os.sep.join(file_path)) 35 | assert build_namespace(view) == 'folder3\\folder4' 36 | def testInsert_namespace_statemenWithoutPhpStatement(self): 37 | namespace = 'test1\\test2\\test3' 38 | sel = Mock() 39 | sel.begin = Mock(return_value=None) 40 | view = Mock() 41 | view.find = Mock(return_value=None) 42 | view.find_all = Mock(return_value=[]) 43 | view.sel = Mock(return_value=[sel]) 44 | insert_namespace_statement(view, None, namespace) 45 | view.insert.assert_called_once_with(None, unittest.mock.ANY, "namespace " + namespace + ";\n") 46 | def testInsert_namespace_statemenWithPhpStatement(self): 47 | namespace = 'test1\\test2\\test3' 48 | view = Mock() 49 | view.find_all = Mock(return_value=['0']) 50 | insert_namespace_statement(view, None, namespace) 51 | view.replace.assert_called_once_with(None, unittest.mock.ANY, "namespace " + namespace + ";") 52 | if __name__ == "__main__": 53 | unittest.main() -------------------------------------------------------------------------------- /namespaces.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | def is_php_file(view): 4 | if view.file_name().endswith('.php'): 5 | return True 6 | return False 7 | 8 | def is_file_opened(window, view): 9 | for wview in window.views(): 10 | if wview.id() == view.id(): 11 | return True 12 | return False 13 | 14 | def close_overlay(window, currentView): 15 | if not is_file_opened(window, window.active_view()): 16 | window.run_command('close', []) 17 | else: 18 | window.focus_view(currentView) 19 | window.run_command('hide_overlay', []) 20 | 21 | def get_namespace(window): 22 | rg = window.active_view().find('namespace (.*);', 0) 23 | snamespace = window.active_view().substr(rg)[10:][:-1] 24 | rg = window.active_view().find('\n([a-z ]+)?(class|interface|trait) [a-zA-Z0-9]+', 0) 25 | sclass = window.active_view().substr(rg) 26 | sclass = sclass[(sclass.rindex(' ')+1):] 27 | return snamespace+'\\'+sclass 28 | 29 | def build_namespace(view): 30 | settings = view.settings() 31 | limits = settings.get('php_namespace.stop_folders') 32 | folders = view.file_name().split(os.sep) 33 | for limit in limits: 34 | if limit in folders: 35 | folders = folders[folders.index(limit):] 36 | return "\\".join(folders[1:-1]) 37 | 38 | def insert_use_statement(view, namespace): 39 | instruct = 'use '+namespace+';' 40 | edit = view.begin_edit() 41 | regions = view.find_all('\nuse (.*);', 0) 42 | if 0 == len(regions): 43 | region = view.find('namespace (.*);', 0) 44 | region = view.full_line(region) 45 | text = view.substr(region) 46 | view.replace(edit, region, text + "\n" + instruct + "\n") 47 | else: 48 | region = view.full_line(regions[-1]) 49 | text = view.substr(region) 50 | view.replace(edit, region, text + instruct + "\n") 51 | 52 | def insert_namespace_statement(view, edit, namespace): 53 | if '' != namespace: 54 | full_namespace = "namespace " + namespace + ";" 55 | region = view.find('namespace (.*);', 0) 56 | if region is None: 57 | regions = view.find_all('<\?php', 0) 58 | 59 | if 0 == len(regions): 60 | for sel in view.sel(): 61 | view.insert(edit, sel.begin(), full_namespace + "\n") 62 | else: 63 | region = view.line(regions[-1]) 64 | view.insert(edit, region.end(), "\n\n" + full_namespace) 65 | else: 66 | region = view.line(region) 67 | view.replace(edit, region, full_namespace) 68 | -------------------------------------------------------------------------------- /Main.sublime-menu: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "caption": "Preferences", 4 | "mnemonic": "n", 5 | "id": "preferences", 6 | "children": 7 | [ 8 | { 9 | "caption": "Package Settings", 10 | "mnemonic": "P", 11 | "id": "package-settings", 12 | "children": 13 | [ 14 | { 15 | "caption": "PhpNamespace", 16 | "children": 17 | [ 18 | { 19 | "command": "open_file", 20 | "args": {"file": "${packages}/PhpNamespace/Base File.sublime-settings"}, 21 | "caption": "Settings – Default" 22 | }, 23 | { 24 | "command": "open_file", 25 | "args": {"file": "${packages}/User/Base File.sublime-settings"}, 26 | "caption": "Settings – User" 27 | }, 28 | { 29 | "command": "open_file", 30 | "args": { 31 | "file": "${packages}/PhpNamespace/Default (Windows).sublime-keymap", 32 | "platform": "Windows" 33 | }, 34 | "caption": "Key Bindings – Default" 35 | }, 36 | { 37 | "command": "open_file", 38 | "args": { 39 | "file": "${packages}/PhpNamespace/Default (OSX).sublime-keymap", 40 | "platform": "OSX" 41 | }, 42 | "caption": "Key Bindings – Default" 43 | }, 44 | { 45 | "command": "open_file", 46 | "args": { 47 | "file": "${packages}/PhpNamespace/Default (Linux).sublime-keymap", 48 | "platform": "Linux" 49 | }, 50 | "caption": "Key Bindings – Default" 51 | }, 52 | { 53 | "command": "open_file", 54 | "args": { 55 | "file": "${packages}/User/Default (Windows).sublime-keymap", 56 | "platform": "Windows" 57 | }, 58 | "caption": "Key Bindings – User" 59 | }, 60 | { 61 | "command": "open_file", 62 | "args": { 63 | "file": "${packages}/User/Default (OSX).sublime-keymap", 64 | "platform": "OSX" 65 | }, 66 | "caption": "Key Bindings – User" 67 | }, 68 | { 69 | "command": "open_file", 70 | "args": { 71 | "file": "${packages}/User/Default (Linux).sublime-keymap", 72 | "platform": "Linux" 73 | }, 74 | "caption": "Key Bindings – User" 75 | }, 76 | { "caption": "-" } 77 | ] 78 | } 79 | ] 80 | } 81 | ] 82 | } 83 | ] 84 | --------------------------------------------------------------------------------