├── .gitignore ├── user_templates.py ├── messages.json ├── php-getters-setters.sublime-settings ├── messages ├── install.md ├── 1.0.7.md ├── 2.0.0.md └── 1.0.8.md ├── Default.sublime-commands ├── Context.sublime-menu ├── packages.json ├── Changelog.md ├── LICENSE.md ├── Main.sublime-menu ├── Readme.md └── php-getter-setter.py /.gitignore: -------------------------------------------------------------------------------- 1 | test*.php 2 | getter-setter.pyc 3 | *.copy 4 | .DS_Store 5 | -------------------------------------------------------------------------------- /user_templates.py: -------------------------------------------------------------------------------- 1 | print('==== USER TEMPLATES ===') 2 | 3 | class BoringTemplate(object): 4 | name = "boring" 5 | getter = "foo" 6 | setter = "bar" 7 | -------------------------------------------------------------------------------- /messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "install": "messages/install.md", 3 | "1.0.8": "messages/1.0.8.md", 4 | "1.0.7": "messages/1.0.7.md", 5 | "2.0.0": "messages/2.0.0.md" 6 | } 7 | -------------------------------------------------------------------------------- /php-getters-setters.sublime-settings: -------------------------------------------------------------------------------- 1 | { 2 | // user defined templates to load 3 | "registerTemplates": [], 4 | 5 | // the template used to generate code 6 | "template": "PSR2", 7 | 8 | // if docblock says variable id any of the following do not add type hinting to functions 9 | "type_hint_ignore": ["mixed", "int", "integer", "double", "float", "number", "string", "boolean", "bool", "numeric", "unknown"], 10 | } 11 | -------------------------------------------------------------------------------- /messages/install.md: -------------------------------------------------------------------------------- 1 | 2 | Thank you for installing php getters and setters. 3 | 4 | If you have any questions or found a bug fell free to contact me at nuno@francodacosta.com 5 | 6 | For bugs open an issue on github https://github.com/francodacosta/sublime-php-getters-setters/issues 7 | 8 | Hope you enjoy it. 9 | 10 | 11 | =========================================== 12 | == Follow me on twitter @NunoFrancoCosta == 13 | =========================================== -------------------------------------------------------------------------------- /messages/1.0.7.md: -------------------------------------------------------------------------------- 1 | 2 | New on 1.0.7 3 | ============ 4 | 5 | * support for snake case coding style 6 | * templates can be overridden 7 | * settings can be changed by you 8 | 9 | 10 | If you have any questions or found a bug fell free to contact me at nuno@francodacosta.com 11 | 12 | For bugs open an issue on github https://github.com/francodacosta/sublime-php-getters-setters/issues 13 | 14 | Hope you enjoy it. 15 | 16 | 17 | 18 | and now for some shameless self promotion: 19 | 20 | =========================================== 21 | == Follow me on twitter @NunoFrancoCosta == 22 | =========================================== -------------------------------------------------------------------------------- /messages/2.0.0.md: -------------------------------------------------------------------------------- 1 | 2 | New on 2.0.0 3 | ============ 4 | 5 | This is a beta version, the plugin was ported to st3, currently the "generate for ..." is not working 6 | 7 | 8 | If you have any questions or found a bug fell free to contact me at nuno@francodacosta.com 9 | 10 | For bugs open an issue on github https://github.com/francodacosta/sublime-php-getters-setters/issues 11 | 12 | Hope you enjoy it. 13 | 14 | 15 | 16 | and now for some shameless self promotion: 17 | 18 | =========================================== 19 | == Follow me on twitter @NunoFrancoCosta == 20 | =========================================== 21 | -------------------------------------------------------------------------------- /Default.sublime-commands: -------------------------------------------------------------------------------- 1 | [ 2 | 3 | { 4 | "caption": "PHP: Generate Getters and Setters", 5 | "command": "php_generate_getters_setters" 6 | }, 7 | { 8 | "caption": "PHP: Generate Getters", 9 | "command": "php_generate_getters" 10 | }, 11 | { 12 | "caption": "PHP: Generate Setters", 13 | "command": "php_generate_getters" 14 | }, 15 | { 16 | "command": "php_generate_getter_for", 17 | "caption": "Generate Getter for ..." 18 | }, 19 | { 20 | "command": "php_generate_setter_for", 21 | "caption": "Generate Setter for ..." 22 | }, 23 | { "command": "php_generate_getter_setter_for", "caption": "Generate Getter and Setter for ..." }, 24 | ] 25 | -------------------------------------------------------------------------------- /messages/1.0.8.md: -------------------------------------------------------------------------------- 1 | 2 | New on 1.0.8 3 | ============ 4 | 5 | * support for fluent interface 6 | 7 | We now support fluent interfaces, when generating setters you will be asked what to do. 8 | You can disable or enable this feature in the settings. see Readme.md for information 9 | 10 | 11 | If you have any questions or found a bug fell free to contact me at nuno@francodacosta.com 12 | 13 | For bugs open an issue on github https://github.com/francodacosta/sublime-php-getters-setters/issues 14 | 15 | Hope you enjoy it. 16 | 17 | 18 | 19 | and now for some shameless self promotion: 20 | 21 | =========================================== 22 | == Follow me on twitter @NunoFrancoCosta == 23 | =========================================== -------------------------------------------------------------------------------- /Context.sublime-menu: -------------------------------------------------------------------------------- 1 | [ 2 | { "caption": "-" }, 3 | { 4 | "caption": "Getters and Setters", 5 | "children": 6 | [ 7 | { "command": "php_generate_getter_for", "caption": "Generate Getter for ..." }, 8 | { "command": "php_generate_setter_for", "caption": "Generate Setter for ..." }, 9 | { "command": "php_generate_getter_setter_for", "caption": "Generate Getter and Setter for ..." }, 10 | { "caption" : "-" }, 11 | { "command": "php_generate_getters_setters", "caption": "Generate All" }, 12 | { "command": "php_generate_getters", "caption": "Generate Getters" }, 13 | { "command": "php_generate_setters", "caption": "Generate setters" }, 14 | { "command": "php_generate_getters_setter_unavailable", "caption": "" } 15 | ] 16 | } 17 | ] 18 | -------------------------------------------------------------------------------- /packages.json: -------------------------------------------------------------------------------- 1 | { 2 | "schema_version": "2.0", 3 | 4 | "packages": [ 5 | 6 | { 7 | "name": "PHP Getters and Setters", 8 | "author": "Nuno Franco da Costa", 9 | "details": "https://github.com/francodacosta/sublime-php-getters-setters", 10 | "labels": ["auto-complete", "php", "snippets", "code generation", "text manipulation", "formatting"], 11 | "releases": [ 12 | { 13 | "date": "2013-09-06 00:00:00", 14 | "version": "1.0.10", 15 | "sublime_text": "<3000", 16 | "url": "https://nodeload.github.com/francodacosta/sublime-php-getters-setters/zip/1.0.10" 17 | }, 18 | { 19 | "sublime_text": ">=3000", 20 | "details": "https://github.com/francodacosta/sublime-php-getters-setters/tags" 21 | } 22 | ] 23 | } 24 | 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /Changelog.md: -------------------------------------------------------------------------------- 1 | 2.0.8 2 | ====== 3 | * bug fix - separator in contex menu 4 | 5 | 2.0.7 6 | ====== 7 | * bug fix 8 | 9 | 2.0.6 10 | ====== 11 | * bug fix 12 | 13 | 2.0.5 14 | ====== 15 | * generate getter and setter for 16 | 17 | 2.0.4 18 | ====== 19 | * generate for ... now works with st3 20 | 21 | 2.0.2 22 | ====== 23 | * st3 version works out of the box (no more copying the templates folder) 24 | * user can overwrite the templates as will 25 | 26 | 2.0.1 27 | ====== 28 | * st3 bugfixes 29 | 30 | 2.0.0 31 | ====== 32 | * st3 support 33 | 34 | 1.0.10 35 | ====== 36 | * supports tabs 37 | * templates human radable var names 38 | 39 | 1.0.9 40 | ===== 41 | * fixed template path 42 | 43 | 1.0.8 44 | ===== 45 | * support for fluent interfaces 46 | 47 | 1.0.7 48 | ===== 49 | * refactored settings parser (moved back to sublime parser) 50 | * templates folder can be specified in settings 51 | * coding style can be specified in settings 52 | 53 | 1.0.6 54 | ===== 55 | * function names in camel case are done properly now 56 | 57 | 1.0.5 58 | ===== 59 | * parser does not crash when parsing doctrine annotations 60 | 61 | 1.0.4 62 | ===== 63 | * added a few more types to type hing ignore (integer, float) 64 | * Generate getter or setter for a single variable 65 | 66 | 1.0.3 67 | ===== 68 | * proper camelCase of function names 69 | 70 | 1.0.2 71 | ===== 72 | * fixed bug preventing static variables to be found 73 | 74 | 1.0.1 75 | ===== 76 | * Allowing multiple types in @var, ex: null | array 77 | 78 | 79 | 1.0.0 80 | ===== 81 | * Initial Version 82 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | New BSD License 2 | =============== 3 | 4 | Copyright (c) 2012, Stuart Herbert and contributors 5 | All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions are met: 9 | 10 | * Redistributions of source code must retain the above copyright notice, 11 | this list of conditions and the following disclaimer. 12 | * Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | * Neither the names of the copyright holders nor the names of its 16 | contributors may be used to endorse or promote products derived from this 17 | software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 23 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 | POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /Main.sublime-menu: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "id": "tools", 4 | "caption": "Tools", 5 | "children": 6 | [ 7 | { 8 | "caption": "PHP Getters and Setters...", 9 | "command": "show_overlay", 10 | "args": {"overlay": "command_palette", "text": "PHP: Generate" } 11 | } 12 | ] 13 | }, 14 | { 15 | "caption": "Preferences", 16 | "mnemonic": "n", 17 | "id": "preferences", 18 | "children": 19 | [ 20 | { 21 | "caption": "Package Settings", 22 | "mnemonic": "P", 23 | "id": "package-settings", 24 | "children": 25 | [ 26 | { 27 | "caption": "PHP Getters and Setters", 28 | "children": 29 | [ 30 | { 31 | "command": "open_file", 32 | "args": {"file": "${packages}/PHP Getters and Setters/php-getters-setters.sublime-settings"}, 33 | "caption": "Settings – Default" 34 | }, 35 | { 36 | "command": "open_file", 37 | "args": {"file": "${packages}/User/php-getters-setters.sublime-settings"}, 38 | "caption": "Settings – User" 39 | } 40 | 41 | ] 42 | } 43 | ] 44 | } 45 | ] 46 | } 47 | ] 48 | -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | PHP Getters and Setters 2 | ======================= 3 | 4 | 5 | With PHP Getters and Setters you can automatically generate _Getters_ and _Setters_ for your php classes. 6 | 7 | Features: 8 | --------- 9 | 10 | * Generate Getters, Setters or Both 11 | * Can be applied to all class properties or just to a single one 12 | * Description, Type and Type Hinting automatically discovered from the variable docblock 13 | * fully customizable templates 14 | 15 | Usage Instruction: 16 | ------------------ 17 | 18 | 1. Generate PHP code 19 | 20 | ```php 21 | class test 22 | { 23 | /** 24 | * foo container 25 | * 26 | * @var AbcClass 27 | */ 28 | private $foo; 29 | } 30 | ``` 31 | 32 | 2. Go to Tools -> PHP Getters and Setter 33 | 3. Getter and Setter will be generated: 34 | 35 | ```php 36 | class test 37 | { 38 | /** 39 | * foo container 40 | * 41 | * @var AbcClass 42 | */ 43 | private $foo; 44 | 45 | /** 46 | * Gets the foo container. 47 | * 48 | * @return AbcClass 49 | */ 50 | public function getFoo() 51 | { 52 | return $this->foo; 53 | } 54 | 55 | /** 56 | * Sets the foo container. 57 | * 58 | * @param AbcClass $foo the foo 59 | */ 60 | private function _setFoo(AbcClass $foo) 61 | { 62 | $this->foo = $foo; 63 | 64 | return $this; 65 | } 66 | } 67 | ``` 68 | 69 | As you can see if get to trouble of commenting your variables, the generated functions can be used without modification. 70 | 71 | This is an huge time saver! 72 | 73 | Usage 74 | ----- 75 | 76 | Commands available are: 77 | 78 | * Generate Getters and Setters 79 | * Generate Getter 80 | * Generate Setter 81 | * Generate Getter for... 82 | * Generate Setter for... 83 | 84 | These can be accesed via the context menu (right click on the source of any open PHP file) or the command pallette. The currently open file *must* be a PHP file. 85 | 86 | Settings Reference 87 | ------------------ 88 | 89 | ###ignore_visibility 90 | _type_ : **boolean** 91 | 92 | _default_ : **false** 93 | 94 | _description_: ignore visibilty for setters generation 95 | 96 | ###registerTemplates 97 | _type_ : **array** 98 | 99 | _default_: **[]** 100 | 101 | _description_: the user templates to load 102 | 103 | ###template 104 | _type_ : **string** 105 | 106 | _default_: **camelCaseFluent** 107 | 108 | _description_: the template to use 109 | 110 | ### type_hint_ignore 111 | _type_: **list of strings** 112 | 113 | _default_: **["mixed", "int","integer", "double", "float", "number", "string", "boolean", "bool", "numeric", "unknown"]** 114 | 115 | _description_: if the property has one of the types listed type hinting will not be used 116 | 117 | ### setter_before_getter 118 | _type_: **boolean** 119 | 120 | _default_: **false** 121 | 122 | _description_: Set to true to generate setter code before getters 123 | 124 | Creating your own template 125 | -------------------------- 126 | 127 | 128 | [package-dir] is your [package directory](http://docs.sublimetext.info/en/sublime-text-3/basic_concepts.html#the-packages-directory). 129 | 130 | * Make a directory called ```[package-dir]/PHP Getters and Setters```. 131 | * Put the following in a file at ```[package-dir]/PHP Getters and Setters/user_templates.py```. 132 | ``` 133 | class myTemplate(object): 134 | name = "myTemplate" 135 | style = 'camelCase' # can also be snakeCase 136 | getter = """ 137 | /** 138 | * Gets the %(description)s. 139 | * 140 | * @return %(type)s 141 | */ 142 | public function get%(normalizedName)s() 143 | { 144 | return $this->%(name)s; 145 | } 146 | """ 147 | 148 | setter = """ 149 | /** 150 | * Sets the %(description)s. 151 | * 152 | * @param %(type)s $%(name)s the %(humanName)s 153 | * 154 | * @return self 155 | */ 156 | public function set%(normalizedName)s(%(typeHint)s $%(name)s) 157 | { 158 | $this->%(name)s = $%(name)s; 159 | } 160 | """ 161 | ``` 162 | * Edit the parts between setter and getter how you want. 163 | * Edit your user settings for this package. On OSX that's ```Preferences | Package Settings | PHP Getters and Setters | Settings - User```. 164 | * Add the following settings 165 | ``` 166 | // user defined templates to load 167 | "registerTemplates" : [ "myTemplate" ], 168 | 169 | // the template used to generate code 170 | "template" : "myTemplate", 171 | ``` 172 | * restart sublime to use the new template 173 | 174 | -------------------------------------------------------------------------------- /php-getter-setter.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import re 3 | import sublime 4 | import sublime_plugin 5 | 6 | # sys.path.append( 7 | # os.path.join( 8 | # os.path.dirname(os.path.realpath(__file__)) 9 | # ) 10 | # ) 11 | from .user_templates import * 12 | 13 | 14 | def msg(msg): 15 | print ("[PHP Getters and Setters] %s" % msg) 16 | 17 | class Prefs: 18 | """ 19 | Plugin preferences 20 | """ 21 | def __init__(self): 22 | self.loaded = False 23 | self.data = {} 24 | 25 | def get(self, name): 26 | if (False == self.loaded): 27 | self.load() 28 | 29 | return self.data[name] 30 | 31 | def load(self): 32 | if self.loaded: 33 | return 34 | 35 | settings = sublime.load_settings('php-getters-setters.sublime-settings') 36 | 37 | self.data['typeHintIgnore'] = settings.get('type_hint_ignore') 38 | msg("ignored type hinting var types %s" % self.data['typeHintIgnore']) 39 | 40 | self.data['template'] = settings.get('template') 41 | msg("template is '%s'" % self.data['template']) 42 | 43 | self.data['registerTemplates'] = settings.get('registerTemplates', []) 44 | msg("register extra user templates %s" % self.data['registerTemplates']) 45 | 46 | self.data['ignoreVisibility'] = settings.get('ignore_visibility', []) 47 | msg("ignoring visibility to getters and setters") 48 | 49 | self.setterBeforeGetter = settings.get('setter_before_getter', False) 50 | msg("setterBeforeGetter is %s" % str(self.setterBeforeGetter)) 51 | 52 | self.loaded = True 53 | 54 | class TemplateManager(object): 55 | templates = {} 56 | 57 | def register(self, template): 58 | self.templates[template.name] = template 59 | msg("Registered template : '%s'" % template.name) 60 | 61 | def get(self, name): 62 | return self.templates[name] 63 | 64 | class Variable(object): 65 | def __init__(self, name, visibility, typeName=None, description=None): 66 | self.name = name 67 | self.type = typeName 68 | self.description = description 69 | self.Prefs = Prefs 70 | if self.Prefs.get('ignoreVisibility'): 71 | visibility = 'public' 72 | self.visibility = visibility 73 | self.template = TemplateManager.get(self.Prefs.get('template')) 74 | self.style = self.template.style 75 | 76 | def getName(self): 77 | return self.name 78 | 79 | def getVisibility(self): 80 | return self.visibility 81 | 82 | def getVisibilityPrefix(self): 83 | visibility = self.visibility 84 | Prefix = '' 85 | 86 | if (visibility == 'private'): 87 | Prefix = '_' 88 | 89 | return Prefix 90 | 91 | def getParam(self): 92 | name = self.name 93 | 94 | if (name[0] == '_'): 95 | name = name[1:] 96 | 97 | return name 98 | 99 | def getHumanName(self): 100 | style = self.style 101 | name = self.getName() 102 | 103 | if 'camelCase' == style: 104 | # FIXME how does this differ from the else? 105 | name = ' '.join(re.findall('(?:[^_a-z]{0,2})[^_A-Z]+', name)).lower() 106 | else: 107 | name = name.replace('_', ' ') 108 | 109 | return name 110 | 111 | def getDescription(self): 112 | if self.description is None or "" == self.description: 113 | self.description = 'value of %s' % self.getName() # get description from name 114 | return self.description 115 | 116 | def getPartialFunctionName(self): 117 | style = self.style 118 | name = self.getName() 119 | 120 | if name[0] == '_' and name[1].islower() and name[2].isupper(): 121 | name = name[2:] # _aTest 122 | elif (name[0].islower() and name[1].isupper()): 123 | name = name[1:] # aTest 124 | elif (name[0] == '_'): 125 | name = name[1:] # _test OR _Test 126 | 127 | if 'camelCase' == style: 128 | var = re.sub(r'_([a-z])', lambda pat: pat.group(1).upper(), name) 129 | var = var[0].upper() + var[1:] 130 | var = var.replace("_", "") 131 | else: 132 | var = name 133 | 134 | return var 135 | 136 | def getGetterPrefix(self): 137 | return "is" if 'bool' in self.getType() else "get" 138 | 139 | def getGetterFunctionName(self): 140 | style = self.style 141 | getterPrefix = self.getGetterPrefix() 142 | 143 | if 'camelCase' == style: 144 | return getterPrefix + "%s" % self.getPartialFunctionName() 145 | 146 | return getterPrefix + "_%s" % self.getPartialFunctionName() 147 | 148 | def getSetterPrefix(self): 149 | return "set" 150 | 151 | def getSetterFunctionName(self): 152 | style = self.style 153 | visPrefix = self.getVisibilityPrefix() 154 | setterPrefix = self.getSetterPrefix() 155 | 156 | if 'camelCase' == style: 157 | return visPrefix + setterPrefix + "%s" % self.getPartialFunctionName() 158 | 159 | return visPrefix + setterPrefix + "_%s" % self.getPartialFunctionName() 160 | 161 | def getType(self): 162 | return self.type 163 | 164 | def getTypeHint(self): 165 | if self.type in self.Prefs.get('typeHintIgnore'): 166 | return '' 167 | 168 | if self.type.find(" ") > -1 or self.type.find("|") > -1: 169 | msg("'%s' is more than one type, switching to no type hint" % self.type) 170 | return "" 171 | 172 | return self.type 173 | 174 | 175 | class DocBlock(object): 176 | """ 177 | docblock text to a class 178 | """ 179 | def __init__(self): 180 | self.tags = {} 181 | self.description = '' 182 | 183 | def hasTag(self, name): 184 | return name in self.tags 185 | 186 | def hasDescription(self): 187 | return len(self.description) > 0 188 | 189 | def addTag(self, name, value): 190 | self.tags[name] = value 191 | 192 | def getTag(self, name): 193 | if not self.hasTag(name): 194 | return None 195 | 196 | return self.tags[name] 197 | 198 | def setDescription(self, value): 199 | self.description = value 200 | 201 | def getDescription(self): 202 | return self.description 203 | 204 | def fromText(self, content): 205 | lines = content.split("\n") 206 | description = [] 207 | 208 | for line in lines: 209 | line = line.strip(' \t*/').rstrip('.') 210 | if line.startswith('@'): 211 | nameMatches = re.findall('\@(\w+) (:?.*)[ ]?.*', line) 212 | if len(nameMatches) > 0: 213 | name = nameMatches[0][0] 214 | value = nameMatches[0][1] 215 | 216 | self.addTag(name.strip('@'), value) 217 | # [name, value, other] = line.split(" ", 2) 218 | else: 219 | msg("Error: could not parse line %s" % line) 220 | else: 221 | if len(line) > 0: 222 | description.append(line) 223 | 224 | self.setDescription("\n".join(description).rstrip("\n")) 225 | 226 | 227 | class Parser(object): 228 | """ 229 | parses text to get class variables so that make the magic can happen 230 | """ 231 | def __init__(self, content): 232 | self.content = content 233 | self.functionRegExp = ".*function.*%s\(" 234 | self.variableRegExp = '((?:private|public|protected)[ ]{0,}(?:final|static)?[ ]{0,}(?:\$.*?)[ |=|;].*)\n' 235 | 236 | def getContent(self): 237 | return self.content 238 | 239 | def hasFunction(self, name): 240 | """ 241 | returns true if the function with the name _name_ is found in the code 242 | """ 243 | content = self.getContent() 244 | regExp = self.functionRegExp % name 245 | 246 | return re.search(regExp, content) is not None 247 | 248 | def _getDockBlockOfVariable(self, line): 249 | content = self.getContent() 250 | matchPos = content.find(line) 251 | 252 | lineByLine = content[:matchPos].split("\n") 253 | lineByLine.reverse() 254 | commentStart = 0 255 | commentEnd = 0 256 | 257 | for n in range(len(lineByLine)): 258 | line = lineByLine[n].strip() 259 | if "\n" == line: 260 | continue 261 | 262 | elif "\r\n" == line: 263 | continue 264 | 265 | elif "" == line: 266 | continue 267 | 268 | elif '*/' == line: 269 | commentStart = n + 1 270 | 271 | elif '/**' == line: 272 | commentEnd = n 273 | break 274 | 275 | elif 0 == commentStart: 276 | break 277 | 278 | if commentStart == commentEnd: 279 | return "" 280 | 281 | if commentStart == 0 or commentEnd == 0: 282 | return "" 283 | 284 | result = lineByLine[commentStart:commentEnd] 285 | result.reverse() 286 | 287 | return "\n".join(result) 288 | 289 | def _processVariable(self, line): 290 | """ 291 | Returns a Variable object populated from the parsed code 292 | """ 293 | nameMatches = re.findall('\$(.*?)[ |=|;]', line) 294 | name = "Unknown" 295 | if len(nameMatches) >= 0: 296 | name = nameMatches[0] 297 | 298 | visibility = 'public' 299 | visibilityMatches = re.findall('^(public|protected|private)', line) 300 | 301 | if len(visibilityMatches) >= 0: 302 | visibility = visibilityMatches[0] 303 | 304 | dockBlockText = self._getDockBlockOfVariable(line) 305 | docblock = DocBlock() 306 | docblock.fromText(dockBlockText) 307 | 308 | typeName = 'mixed' 309 | if docblock.hasTag('var'): 310 | typeName = docblock.getTag('var') 311 | description = docblock.getDescription() 312 | 313 | return Variable(name = name, visibility = visibility, typeName = typeName, description = description) 314 | 315 | def getClassVariables(self): 316 | """ 317 | returns a list of Variable objects, created from the parsed code 318 | """ 319 | content = self.getContent() 320 | variablesList = [] 321 | 322 | matches = re.findall(self.variableRegExp, content, re.IGNORECASE) 323 | for match in matches: 324 | variable = self._processVariable(match) 325 | variablesList.append(variable) 326 | 327 | return variablesList 328 | 329 | class Base(sublime_plugin.TextCommand): 330 | def __init__(self, arg): 331 | sublime_plugin.TextCommand.__init__(self, arg) 332 | self.variables = None 333 | self.parser = None 334 | self.Prefs = Prefs 335 | self.onlyForVar = None 336 | 337 | def onlyForVar(self, varName): 338 | self.onlyForVar = varName 339 | 340 | def getContent(self): 341 | return self.view.substr(sublime.Region(0, self.view.size())) 342 | 343 | def getParser(self, content = ''): 344 | self.parser = Parser(content) 345 | 346 | return self.parser 347 | 348 | def findLastBracket(self): 349 | view = self.view 350 | pos = 0 351 | lastPos = 1 352 | 353 | pos = view.find('\{', 0) 354 | 355 | while True: 356 | pos = view.find('\}', pos.end()) 357 | if (pos.begin() == -1): 358 | break 359 | lastPos = pos.begin() 360 | 361 | return lastPos 362 | 363 | def getVariables(self, parser): 364 | filename = self.view.file_name() 365 | parser = self.getParser(open(filename).read()) 366 | self.variables = parser.getClassVariables() 367 | 368 | return self.variables 369 | 370 | def generateFunctionCode(self, template, variable): 371 | substitutions = { 372 | "name": variable.getName(), 373 | "param": variable.getParam(), 374 | "visibility": variable.getVisibility(), 375 | "visibilityPrefix": variable.getVisibilityPrefix(), 376 | "type": variable.getType(), 377 | "normalizedName": variable.getPartialFunctionName(), 378 | "description": variable.getDescription(), 379 | "typeHint": variable.getTypeHint(), 380 | "humanName": variable.getHumanName(), 381 | "getterPrefix": variable.getGetterPrefix(), 382 | "setterPrefix": variable.getSetterPrefix() 383 | } 384 | 385 | return template % substitutions 386 | 387 | def generateGetterFunction(self, parser, variable): 388 | 389 | if parser.hasFunction(variable.getGetterFunctionName()): 390 | msg("function %s already present, skipping" % variable.getGetterFunctionName()) 391 | return '' 392 | 393 | template = TemplateManager.get(Prefs.get('template')) 394 | code = self.generateFunctionCode(template.getter, variable) 395 | 396 | return code 397 | 398 | def generateSetterFunction(self, parser, variable): 399 | 400 | if parser.hasFunction(variable.getSetterFunctionName()): 401 | msg("function %s already present, skipping" % variable.getSetterFunctionName()) 402 | return '' 403 | 404 | template = TemplateManager.get(Prefs.get('template')) 405 | code = self.generateFunctionCode(template.setter, variable) 406 | # if type hinting is not to be show we get "( " instead of ( 407 | code = code.replace('( ', '(') 408 | 409 | return code 410 | 411 | def writeAtEnd(self, edit, text): 412 | lastPos = self.findLastBracket() 413 | self.view.insert(edit, lastPos, text) 414 | 415 | def isPhpSyntax(self): 416 | return re.search(".*\PHP.sublime-syntax", self.view.settings().get('syntax')) is not None 417 | 418 | def is_enabled(self): 419 | return self.isPhpSyntax() 420 | 421 | def is_visible(self): 422 | return self.is_enabled() 423 | 424 | 425 | class PhpGenerateFor(Base): 426 | what = 'getter' 427 | 428 | def run(self, edit): 429 | self.edit = edit 430 | 431 | parser = self.getParser(self.getContent()) 432 | 433 | self.vars = [] 434 | 435 | for variable in parser.getClassVariables(): 436 | item = [variable.getName(), variable.getDescription()] 437 | self.vars.append(item) 438 | 439 | self.view.window().show_quick_panel(self.vars, self.write) 440 | 441 | def write(self, index): 442 | name = self.vars[index][0] 443 | parser = self.getParser(self.getContent()) 444 | for variable in parser.getClassVariables(): 445 | if name == variable.getName(): 446 | if 'getter' == self.what: 447 | # code = self.generateGetterFunction(parser, variable) 448 | self.view.run_command('php_generate_getters', {'name': name}) 449 | elif 'setter' == self.what: 450 | self.view.run_command('php_generate_setters', {'name': name}) 451 | else: 452 | self.view.run_command('php_generate_getters_setters', {'name': name}) 453 | # self.writeAtEnd(self.edit, code) 454 | 455 | class PhpGenerateGetterForCommand(PhpGenerateFor): 456 | what = 'getter' 457 | 458 | class PhpGenerateSetterForCommand(PhpGenerateFor): 459 | what = 'setter' 460 | 461 | class PhpGenerateGetterSetterForCommand(PhpGenerateFor): 462 | what = 'getter-setter' 463 | 464 | class PhpGenerateGettersCommand(Base): 465 | def run(self, edit, **args): 466 | if not 'name' in args: 467 | args['name'] = None 468 | 469 | parser = self.getParser(self.getContent()) 470 | code = '' 471 | for variable in parser.getClassVariables(): 472 | if args['name'] is not None and variable.getName() != args['name']: 473 | continue 474 | 475 | code += self.generateGetterFunction(parser, variable) 476 | 477 | self.writeAtEnd(edit, code) 478 | 479 | class PhpGenerateSettersCommand(Base): 480 | def run(self, edit, **args): 481 | if not 'name' in args: 482 | args['name'] = None 483 | 484 | parser = self.getParser(self.getContent()) 485 | code = '' 486 | for variable in parser.getClassVariables(): 487 | if args['name'] is not None and variable.getName() != args['name']: 488 | continue 489 | 490 | code += self.generateSetterFunction(parser, variable) 491 | 492 | self.writeAtEnd(edit, code) 493 | 494 | class PhpGenerateGettersSettersCommand(Base): 495 | def run(self, edit, **args): 496 | if not 'name' in args: 497 | args['name'] = None 498 | 499 | parser = self.getParser(self.getContent()) 500 | code = '' 501 | for variable in parser.getClassVariables(): 502 | if args['name'] is not None and variable.getName() != args['name']: 503 | continue 504 | 505 | if self.Prefs.setterBeforeGetter: 506 | code += self.generateSetterFunction(parser, variable) 507 | code += self.generateGetterFunction(parser, variable) 508 | else: 509 | code += self.generateGetterFunction(parser, variable) 510 | code += self.generateSetterFunction(parser, variable) 511 | 512 | self.writeAtEnd(edit, code) 513 | 514 | 515 | class PhpGenerateGettersSetterUnavailable(Base): 516 | def run(self, edit): 517 | pass 518 | 519 | def is_enabled(self): 520 | return False 521 | 522 | def is_visible(self): 523 | return not self.isPhpSyntax() 524 | 525 | def description(self): 526 | return "Only available for PHP syntax buffers" 527 | 528 | class PSR2(object): 529 | name = "PSR2" 530 | style = 'camelCase' 531 | 532 | getter = """ 533 | /** 534 | * @return %(type)s 535 | */ 536 | public function %(getterPrefix)s%(normalizedName)s() 537 | { 538 | return $this->%(name)s; 539 | } 540 | """ 541 | 542 | setter = """ 543 | /** 544 | * @param %(type)s $%(name)s 545 | * 546 | * @return self 547 | */ 548 | public function %(setterPrefix)s%(normalizedName)s(%(typeHint)s $%(name)s) 549 | { 550 | $this->%(name)s = $%(name)s; 551 | 552 | return $this; 553 | } 554 | """ 555 | 556 | class camelCase(object): 557 | name = "camelCase" 558 | style = 'camelCase' 559 | getter = """ 560 | /** 561 | * Gets the %(description)s. 562 | * 563 | * @return %(type)s 564 | */ 565 | public function get%(normalizedName)s() 566 | { 567 | return $this->%(name)s; 568 | } 569 | """ 570 | 571 | setter = """ 572 | /** 573 | * Sets the %(description)s. 574 | * 575 | * @param %(type)s $%(name)s the %(humanName)s 576 | * 577 | * @return self 578 | */ 579 | %(visibility)s function %(visibilityPrefix)sset%(normalizedName)s(%(typeHint)s $%(param)s) 580 | { 581 | $this->%(name)s = $%(param)s; 582 | 583 | return $this; 584 | } 585 | """ 586 | 587 | class camelCaseFluent(camelCase): 588 | name = "camelCaseFluent" 589 | style = 'camelCase' 590 | setter = """ 591 | /** 592 | * Sets the %(description)s. 593 | * 594 | * @param %(type)s $%(name)s the %(humanName)s 595 | * 596 | * @return self 597 | */ 598 | %(visibility)s function %(visibilityPrefix)sset%(normalizedName)s(%(typeHint)s $%(param)s) 599 | { 600 | $this->%(name)s = $%(param)s; 601 | 602 | return $this; 603 | } 604 | """ 605 | 606 | class snakeCase(object): 607 | name = "snakeCase" 608 | style = 'snakeCase' 609 | getter = """ 610 | /** 611 | * Gets the %(description)s. 612 | * 613 | * @return %(type)s 614 | */ 615 | public function get_%(normalizedName)s() 616 | { 617 | return $this->%(name)s; 618 | } 619 | """ 620 | setter = """ 621 | /** 622 | * Sets the %(description)s. 623 | * 624 | * @param %(type)s $%(name)s the %(name)s 625 | * 626 | * @return self 627 | */ 628 | %(visibility)s function %(visibilityPrefix)sset_%(normalizedName)s(%(typeHint)s $%(param)s) 629 | { 630 | $this->%(name)s = $%(param)s; 631 | 632 | return $this; 633 | } 634 | """ 635 | 636 | class snakeCaseFluent(snakeCase): 637 | name = "snakeCaseFluent" 638 | style = 'snakeCase' 639 | setter = """ 640 | /** 641 | * Sets the %(description)s. 642 | * 643 | * @param %(type)s $%(name)s the %(name)s 644 | * 645 | * @return self 646 | */ 647 | %(visibility)s function %(visibilityPrefix)sset_%(normalizedName)s(%(typeHint)s $%(param)s) 648 | { 649 | $this->%(name)s = $%(param)s; 650 | 651 | return $this; 652 | } 653 | """ 654 | 655 | Prefs = Prefs() 656 | 657 | TemplateManager = TemplateManager() 658 | 659 | def plugin_loaded(): 660 | TemplateManager.register(PSR2()) 661 | TemplateManager.register(camelCase()) 662 | TemplateManager.register(camelCaseFluent()) 663 | TemplateManager.register(snakeCase()) 664 | TemplateManager.register(snakeCaseFluent()) 665 | 666 | for template in Prefs.get('registerTemplates'): 667 | TemplateManager.register(eval(template+'()')) 668 | --------------------------------------------------------------------------------