├── Default (Linux).sublime-keymap ├── Default (OSX).sublime-keymap ├── Default (Windows).sublime-keymap ├── Method.sublime-commands ├── commands.py ├── context.py ├── demo └── demo.py ├── leave_only_current_test.sublime-macro ├── leave_only_current_test_go.sublime-macro ├── license.md ├── method.py ├── readme.md ├── snippets ├── coffee-method-call-null.sublime-snippet ├── coffee-method-call.sublime-snippet ├── coffee-method.sublime-snippet ├── go-method-call-null.sublime-snippet ├── go-method-call.sublime-snippet ├── go-method.sublime-snippet ├── js-method-call-null.sublime-snippet ├── js-method-call.sublime-snippet ├── js-method.sublime-snippet ├── php-method.sublime-snippet ├── python-method-call-null.sublime-snippet ├── python-method-call.sublime-snippet ├── python-method.sublime-snippet ├── ruby-method-call-null.sublime-snippet ├── ruby-method-call.sublime-snippet └── ruby-method.sublime-snippet └── uncomment_bookmarks.sublime-macro /Default (Linux).sublime-keymap: -------------------------------------------------------------------------------- 1 | [ 2 | 3 | { 4 | "keys": ["ctrl+m", "ctrl+,"], 5 | "command": "create_method", 6 | "args": { 7 | "index": "current" 8 | }, 9 | "context": [ 10 | {"key": "setting.sublime_enhanced_keybindings", "operator": "equal", "operand": true} 11 | ] 12 | }, 13 | 14 | { 15 | "keys": ["ctrl+m", "ctrl+."], 16 | "command": "create_method", 17 | "args": { 18 | "index": "current", 19 | "after": true 20 | }, 21 | "context": [ 22 | {"key": "setting.sublime_enhanced_keybindings", "operator": "equal", "operand": true} 23 | ] 24 | }, 25 | 26 | { 27 | "keys": ["ctrl+alt+shift+n"], 28 | "command": "create_method", 29 | "args": { 30 | "index": "current", 31 | "after": true 32 | }, 33 | "context": [ 34 | {"key": "setting.sublime_enhanced_keybindings", "operator": "equal", "operand": true} 35 | ] 36 | }, 37 | 38 | { 39 | "keys": ["ctrl+m", "ctrl+0"], 40 | "command": "create_method", 41 | "args": { 42 | "index": 1 43 | }, 44 | "context": [ 45 | {"key": "setting.sublime_enhanced_keybindings", "operator": "equal", "operand": true} 46 | ] 47 | }, 48 | 49 | { 50 | "keys": ["ctrl+m", "ctrl+o"], 51 | "command": "create_method", 52 | "args": { 53 | "index": "protected" 54 | }, 55 | "context": [ 56 | {"key": "setting.sublime_enhanced_keybindings", "operator": "equal", "operand": true} 57 | ] 58 | }, 59 | 60 | { 61 | "keys": ["ctrl+m", "ctrl+i"], 62 | "command": "create_method", 63 | "args": { 64 | "index": "private" 65 | }, 66 | "context": [ 67 | {"key": "setting.sublime_enhanced_keybindings", "operator": "equal", "operand": true} 68 | ] 69 | }, 70 | 71 | { 72 | "keys": ["ctrl+m", "ctrl+l"], 73 | "command": "create_method", 74 | "args": { 75 | "index": "last", 76 | "after": true 77 | }, 78 | "context": [ 79 | {"key": "setting.sublime_enhanced_keybindings", "operator": "equal", "operand": true} 80 | ] 81 | }, 82 | 83 | { 84 | "keys": ["ctrl+m", "0"], 85 | "command": "move_method", 86 | "args": { 87 | "index": 0, 88 | "after": true, 89 | }, 90 | "context": [ 91 | {"key": "setting.sublime_enhanced_keybindings", "operator": "equal", "operand": true} 92 | ] 93 | }, 94 | 95 | { 96 | "keys": ["ctrl+m", "o"], 97 | "command": "move_method", 98 | "args": { 99 | "index": "protected" 100 | }, 101 | "context": [ 102 | {"key": "setting.sublime_enhanced_keybindings", "operator": "equal", "operand": true} 103 | ] 104 | }, 105 | 106 | { 107 | "keys": ["ctrl+m", "i"], 108 | "command": "move_method", 109 | "args": { 110 | "index": "private" 111 | }, 112 | "context": [ 113 | {"key": "setting.sublime_enhanced_keybindings", "operator": "equal", "operand": true} 114 | ] 115 | }, 116 | 117 | { 118 | "keys": ["ctrl+m", "l"], 119 | "command": "move_method", 120 | "args": { 121 | "index": "last", 122 | "after": true 123 | }, 124 | "context": [ 125 | {"key": "setting.sublime_enhanced_keybindings", "operator": "equal", "operand": true} 126 | ] 127 | }, 128 | 129 | { 130 | "keys": ["alt+-"], 131 | "command": "move_method", 132 | "args": { 133 | "index": "-1" 134 | }, 135 | "context": [ 136 | {"key": "setting.sublime_enhanced_keybindings", "operator": "equal", "operand": true} 137 | ] 138 | }, 139 | 140 | { 141 | "keys": ["alt+="], 142 | "command": "move_method", 143 | "args": { 144 | "index": "+1", 145 | "after": true 146 | }, 147 | "context": [ 148 | {"key": "setting.sublime_enhanced_keybindings", "operator": "equal", "operand": true} 149 | ] 150 | }, 151 | 152 | { 153 | "keys": ["alt+n"], 154 | "command": "goto_method", 155 | "args": { 156 | "method": "+1" 157 | }, 158 | "context": [ 159 | {"key": "setting.sublime_enhanced_keybindings", "operator": "equal", "operand": true} 160 | ] 161 | }, 162 | 163 | { 164 | "keys": ["alt+shift+n"], 165 | "command": "goto_method", 166 | "args": { 167 | "method": "-1" 168 | }, 169 | "context": [ 170 | {"key": "setting.sublime_enhanced_keybindings", "operator": "equal", "operand": true} 171 | ] 172 | }, 173 | 174 | { 175 | "keys": ["alt+ctrl+n"], 176 | "command": "goto_method", 177 | "args": { 178 | "method": "current", 179 | "position": "swap" 180 | }, 181 | "context": [ 182 | {"key": "setting.sublime_enhanced_keybindings", "operator": "equal", "operand": true} 183 | ] 184 | }, 185 | 186 | { 187 | "keys": ["ctrl+m", "ctrl+/"], 188 | "command": "goto_method", 189 | "args": { 190 | "method": "last" 191 | }, 192 | "context": [ 193 | {"key": "setting.sublime_enhanced_keybindings", "operator": "equal", "operand": true} 194 | ] 195 | }, 196 | 197 | { 198 | "keys": ["ctrl+m", "ctrl+f"], 199 | "command": "goto_method", 200 | "args": { 201 | "method": "0" 202 | }, 203 | "context": [ 204 | {"key": "setting.sublime_enhanced_keybindings", "operator": "equal", "operand": true} 205 | ] 206 | }, 207 | 208 | { 209 | "keys": ["ctrl+m", "ctrl+n"], 210 | "command": "create_method_space", 211 | "args": { 212 | "index": "current", 213 | "after": true 214 | }, 215 | "context": [ 216 | {"key": "setting.sublime_enhanced_keybindings", "operator": "equal", "operand": true} 217 | ] 218 | }, 219 | 220 | { 221 | "keys": ["ctrl+m", "ctrl+d"], 222 | "command": "delete_method", 223 | "args": { 224 | "method": "current" 225 | }, 226 | "context": [ 227 | {"key": "setting.sublime_enhanced_keybindings", "operator": "equal", "operand": true} 228 | ] 229 | }, 230 | 231 | { 232 | "keys": ["ctrl+m", "ctrl+c"], 233 | "command": "clone_method", 234 | "args": { 235 | "index": "current", 236 | "after": true 237 | }, 238 | "context": [ 239 | {"key": "setting.sublime_enhanced_keybindings", "operator": "equal", "operand": true} 240 | ] 241 | }, 242 | 243 | { 244 | "keys": ["ctrl+m", "ctrl+m"], 245 | "command": "insert_method_name_to_mark", 246 | "args": {}, 247 | "context": [ 248 | {"key": "setting.sublime_enhanced_keybindings", "operator": "equal", "operand": true} 249 | ] 250 | }, 251 | 252 | { 253 | "keys": ["ctrl+m", "ctrl+s"], 254 | "command": "select_methods", 255 | "args": { 256 | "methods": "current" 257 | }, 258 | "context": [ 259 | {"key": "setting.sublime_enhanced_keybindings", "operator": "equal", "operand": true} 260 | ] 261 | }, 262 | 263 | { 264 | "keys": ["ctrl+m", "s"], 265 | "command": "select_methods", 266 | "args": { 267 | "methods": "current", 268 | "body": true 269 | }, 270 | "context": [ 271 | {"key": "setting.sublime_enhanced_keybindings", "operator": "equal", "operand": true} 272 | ] 273 | }, 274 | 275 | { 276 | "keys": ["ctrl+m", "ctrl+q"], 277 | "command": "run_macro_file", 278 | "args": { 279 | "file": "res://Packages/Method/leave_only_current_test.sublime-macro" 280 | }, 281 | "context": [ 282 | {"key": "scope", "operator": "not_regex_contains", "operand": "source.go"}, 283 | {"key": "setting.sublime_enhanced_keybindings", "operator": "equal", "operand": true} 284 | ] 285 | }, 286 | 287 | { 288 | "keys": ["ctrl+m", "ctrl+q"], 289 | "command": "run_macro_file", 290 | "args": { 291 | "file": "res://Packages/Method/leave_only_current_test_go.sublime-macro" 292 | }, 293 | "context": [ 294 | {"key": "scope", "operator": "regex_contains", "operand": "source\\.go"}, 295 | {"key": "setting.sublime_enhanced_keybindings", "operator": "equal", "operand": true} 296 | ] 297 | }, 298 | 299 | { 300 | "keys": ["ctrl+m", "q"], 301 | "command": "run_macro_file", 302 | "args": { 303 | "file": "res://Packages/Method/uncomment_bookmarks.sublime-macro" 304 | }, 305 | "context": [ 306 | {"key": "setting.sublime_enhanced_keybindings", "operator": "equal", "operand": true} 307 | ] 308 | }, 309 | ] -------------------------------------------------------------------------------- /Default (OSX).sublime-keymap: -------------------------------------------------------------------------------- 1 | [ 2 | 3 | { 4 | "keys": ["ctrl+m", "ctrl+,"], 5 | "command": "create_method", 6 | "args": { 7 | "index": "current" 8 | }, 9 | "context": [ 10 | {"key": "setting.sublime_enhanced_keybindings", "operator": "equal", "operand": true} 11 | ] 12 | }, 13 | 14 | { 15 | "keys": ["ctrl+m", "ctrl+."], 16 | "command": "create_method", 17 | "args": { 18 | "index": "current", 19 | "after": true 20 | }, 21 | "context": [ 22 | {"key": "setting.sublime_enhanced_keybindings", "operator": "equal", "operand": true} 23 | ] 24 | }, 25 | 26 | { 27 | "keys": ["ctrl+alt+shift+n"], 28 | "command": "create_method", 29 | "args": { 30 | "index": "current", 31 | "after": true 32 | }, 33 | "context": [ 34 | {"key": "setting.sublime_enhanced_keybindings", "operator": "equal", "operand": true} 35 | ] 36 | }, 37 | 38 | { 39 | "keys": ["ctrl+m", "ctrl+0"], 40 | "command": "create_method", 41 | "args": { 42 | "index": 1 43 | }, 44 | "context": [ 45 | {"key": "setting.sublime_enhanced_keybindings", "operator": "equal", "operand": true} 46 | ] 47 | }, 48 | 49 | { 50 | "keys": ["ctrl+m", "ctrl+o"], 51 | "command": "create_method", 52 | "args": { 53 | "index": "protected" 54 | }, 55 | "context": [ 56 | {"key": "setting.sublime_enhanced_keybindings", "operator": "equal", "operand": true} 57 | ] 58 | }, 59 | 60 | { 61 | "keys": ["ctrl+m", "ctrl+i"], 62 | "command": "create_method", 63 | "args": { 64 | "index": "private" 65 | }, 66 | "context": [ 67 | {"key": "setting.sublime_enhanced_keybindings", "operator": "equal", "operand": true} 68 | ] 69 | }, 70 | 71 | { 72 | "keys": ["ctrl+m", "ctrl+l"], 73 | "command": "create_method", 74 | "args": { 75 | "index": "last", 76 | "after": true 77 | }, 78 | "context": [ 79 | {"key": "setting.sublime_enhanced_keybindings", "operator": "equal", "operand": true} 80 | ] 81 | }, 82 | 83 | { 84 | "keys": ["ctrl+m", "0"], 85 | "command": "move_method", 86 | "args": { 87 | "index": 0, 88 | "after": true, 89 | }, 90 | "context": [ 91 | {"key": "setting.sublime_enhanced_keybindings", "operator": "equal", "operand": true} 92 | ] 93 | }, 94 | 95 | { 96 | "keys": ["ctrl+m", "o"], 97 | "command": "move_method", 98 | "args": { 99 | "index": "protected" 100 | }, 101 | "context": [ 102 | {"key": "setting.sublime_enhanced_keybindings", "operator": "equal", "operand": true} 103 | ] 104 | }, 105 | 106 | { 107 | "keys": ["ctrl+m", "i"], 108 | "command": "move_method", 109 | "args": { 110 | "index": "private" 111 | }, 112 | "context": [ 113 | {"key": "setting.sublime_enhanced_keybindings", "operator": "equal", "operand": true} 114 | ] 115 | }, 116 | 117 | { 118 | "keys": ["ctrl+m", "l"], 119 | "command": "move_method", 120 | "args": { 121 | "index": "last", 122 | "after": true 123 | }, 124 | "context": [ 125 | {"key": "setting.sublime_enhanced_keybindings", "operator": "equal", "operand": true} 126 | ] 127 | }, 128 | 129 | { 130 | "keys": ["alt+-"], 131 | "command": "move_method", 132 | "args": { 133 | "index": "-1" 134 | }, 135 | "context": [ 136 | {"key": "setting.sublime_enhanced_keybindings", "operator": "equal", "operand": true} 137 | ] 138 | }, 139 | 140 | { 141 | "keys": ["alt+="], 142 | "command": "move_method", 143 | "args": { 144 | "index": "+1", 145 | "after": true 146 | }, 147 | "context": [ 148 | {"key": "setting.sublime_enhanced_keybindings", "operator": "equal", "operand": true} 149 | ] 150 | }, 151 | 152 | { 153 | "keys": ["alt+n"], 154 | "command": "goto_method", 155 | "args": { 156 | "method": "+1" 157 | }, 158 | "context": [ 159 | {"key": "setting.sublime_enhanced_keybindings", "operator": "equal", "operand": true} 160 | ] 161 | }, 162 | 163 | { 164 | "keys": ["alt+shift+n"], 165 | "command": "goto_method", 166 | "args": { 167 | "method": "-1" 168 | }, 169 | "context": [ 170 | {"key": "setting.sublime_enhanced_keybindings", "operator": "equal", "operand": true} 171 | ] 172 | }, 173 | 174 | { 175 | "keys": ["alt+ctrl+n"], 176 | "command": "goto_method", 177 | "args": { 178 | "method": "current", 179 | "position": "swap" 180 | }, 181 | "context": [ 182 | {"key": "setting.sublime_enhanced_keybindings", "operator": "equal", "operand": true} 183 | ] 184 | }, 185 | 186 | { 187 | "keys": ["ctrl+m", "ctrl+/"], 188 | "command": "goto_method", 189 | "args": { 190 | "method": "last" 191 | }, 192 | "context": [ 193 | {"key": "setting.sublime_enhanced_keybindings", "operator": "equal", "operand": true} 194 | ] 195 | }, 196 | 197 | { 198 | "keys": ["ctrl+m", "ctrl+f"], 199 | "command": "goto_method", 200 | "args": { 201 | "method": "0" 202 | }, 203 | "context": [ 204 | {"key": "setting.sublime_enhanced_keybindings", "operator": "equal", "operand": true} 205 | ] 206 | }, 207 | 208 | { 209 | "keys": ["ctrl+m", "ctrl+n"], 210 | "command": "create_method_space", 211 | "args": { 212 | "index": "current", 213 | "after": true 214 | }, 215 | "context": [ 216 | {"key": "setting.sublime_enhanced_keybindings", "operator": "equal", "operand": true} 217 | ] 218 | }, 219 | 220 | { 221 | "keys": ["ctrl+m", "ctrl+d"], 222 | "command": "delete_method", 223 | "args": { 224 | "method": "current" 225 | }, 226 | "context": [ 227 | {"key": "setting.sublime_enhanced_keybindings", "operator": "equal", "operand": true} 228 | ] 229 | }, 230 | 231 | { 232 | "keys": ["ctrl+m", "ctrl+c"], 233 | "command": "clone_method", 234 | "args": { 235 | "index": "current", 236 | "after": true 237 | }, 238 | "context": [ 239 | {"key": "setting.sublime_enhanced_keybindings", "operator": "equal", "operand": true} 240 | ] 241 | }, 242 | 243 | { 244 | "keys": ["ctrl+m", "ctrl+m"], 245 | "command": "insert_method_name_to_mark", 246 | "args": {}, 247 | "context": [ 248 | {"key": "setting.sublime_enhanced_keybindings", "operator": "equal", "operand": true} 249 | ] 250 | }, 251 | 252 | { 253 | "keys": ["ctrl+m", "ctrl+s"], 254 | "command": "select_methods", 255 | "args": { 256 | "methods": "current" 257 | }, 258 | "context": [ 259 | {"key": "setting.sublime_enhanced_keybindings", "operator": "equal", "operand": true} 260 | ] 261 | }, 262 | 263 | { 264 | "keys": ["ctrl+m", "s"], 265 | "command": "select_methods", 266 | "args": { 267 | "methods": "current", 268 | "body": true 269 | }, 270 | "context": [ 271 | {"key": "setting.sublime_enhanced_keybindings", "operator": "equal", "operand": true} 272 | ] 273 | }, 274 | 275 | { 276 | "keys": ["ctrl+m", "ctrl+q"], 277 | "command": "run_macro_file", 278 | "args": { 279 | "file": "res://Packages/Method/leave_only_current_test.sublime-macro" 280 | }, 281 | "context": [ 282 | {"key": "setting.sublime_enhanced_keybindings", "operator": "equal", "operand": true} 283 | ] 284 | }, 285 | 286 | { 287 | "keys": ["ctrl+m", "q"], 288 | "command": "run_macro_file", 289 | "args": { 290 | "file": "res://Packages/Method/uncomment_bookmarks.sublime-macro" 291 | }, 292 | "context": [ 293 | {"key": "setting.sublime_enhanced_keybindings", "operator": "equal", "operand": true} 294 | ] 295 | }, 296 | ] -------------------------------------------------------------------------------- /Default (Windows).sublime-keymap: -------------------------------------------------------------------------------- 1 | [ 2 | 3 | { 4 | "keys": ["ctrl+m", "ctrl+,"], 5 | "command": "create_method", 6 | "args": { 7 | "index": "current" 8 | }, 9 | "context": [ 10 | {"key": "setting.sublime_enhanced_keybindings", "operator": "equal", "operand": true} 11 | ] 12 | }, 13 | 14 | { 15 | "keys": ["ctrl+m", "ctrl+."], 16 | "command": "create_method", 17 | "args": { 18 | "index": "current", 19 | "after": true 20 | }, 21 | "context": [ 22 | {"key": "setting.sublime_enhanced_keybindings", "operator": "equal", "operand": true} 23 | ] 24 | }, 25 | 26 | { 27 | "keys": ["ctrl+alt+shift+n"], 28 | "command": "create_method", 29 | "args": { 30 | "index": "current", 31 | "after": true 32 | }, 33 | "context": [ 34 | {"key": "setting.sublime_enhanced_keybindings", "operator": "equal", "operand": true} 35 | ] 36 | }, 37 | 38 | { 39 | "keys": ["ctrl+m", "ctrl+0"], 40 | "command": "create_method", 41 | "args": { 42 | "index": 1 43 | }, 44 | "context": [ 45 | {"key": "setting.sublime_enhanced_keybindings", "operator": "equal", "operand": true} 46 | ] 47 | }, 48 | 49 | { 50 | "keys": ["ctrl+m", "ctrl+o"], 51 | "command": "create_method", 52 | "args": { 53 | "index": "protected" 54 | }, 55 | "context": [ 56 | {"key": "setting.sublime_enhanced_keybindings", "operator": "equal", "operand": true} 57 | ] 58 | }, 59 | 60 | { 61 | "keys": ["ctrl+m", "ctrl+i"], 62 | "command": "create_method", 63 | "args": { 64 | "index": "private" 65 | }, 66 | "context": [ 67 | {"key": "setting.sublime_enhanced_keybindings", "operator": "equal", "operand": true} 68 | ] 69 | }, 70 | 71 | { 72 | "keys": ["ctrl+m", "ctrl+l"], 73 | "command": "create_method", 74 | "args": { 75 | "index": "last", 76 | "after": true 77 | }, 78 | "context": [ 79 | {"key": "setting.sublime_enhanced_keybindings", "operator": "equal", "operand": true} 80 | ] 81 | }, 82 | 83 | { 84 | "keys": ["ctrl+m", "0"], 85 | "command": "move_method", 86 | "args": { 87 | "index": 0, 88 | "after": true, 89 | }, 90 | "context": [ 91 | {"key": "setting.sublime_enhanced_keybindings", "operator": "equal", "operand": true} 92 | ] 93 | }, 94 | 95 | { 96 | "keys": ["ctrl+m", "o"], 97 | "command": "move_method", 98 | "args": { 99 | "index": "protected" 100 | }, 101 | "context": [ 102 | {"key": "setting.sublime_enhanced_keybindings", "operator": "equal", "operand": true} 103 | ] 104 | }, 105 | 106 | { 107 | "keys": ["ctrl+m", "i"], 108 | "command": "move_method", 109 | "args": { 110 | "index": "private" 111 | }, 112 | "context": [ 113 | {"key": "setting.sublime_enhanced_keybindings", "operator": "equal", "operand": true} 114 | ] 115 | }, 116 | 117 | { 118 | "keys": ["ctrl+m", "l"], 119 | "command": "move_method", 120 | "args": { 121 | "index": "last", 122 | "after": true 123 | }, 124 | "context": [ 125 | {"key": "setting.sublime_enhanced_keybindings", "operator": "equal", "operand": true} 126 | ] 127 | }, 128 | 129 | { 130 | "keys": ["alt+-"], 131 | "command": "move_method", 132 | "args": { 133 | "index": "-1" 134 | }, 135 | "context": [ 136 | {"key": "setting.sublime_enhanced_keybindings", "operator": "equal", "operand": true} 137 | ] 138 | }, 139 | 140 | { 141 | "keys": ["alt+="], 142 | "command": "move_method", 143 | "args": { 144 | "index": "+1", 145 | "after": true 146 | }, 147 | "context": [ 148 | {"key": "setting.sublime_enhanced_keybindings", "operator": "equal", "operand": true} 149 | ] 150 | }, 151 | 152 | { 153 | "keys": ["alt+n"], 154 | "command": "goto_method", 155 | "args": { 156 | "method": "+1" 157 | }, 158 | "context": [ 159 | {"key": "setting.sublime_enhanced_keybindings", "operator": "equal", "operand": true} 160 | ] 161 | }, 162 | 163 | { 164 | "keys": ["alt+shift+n"], 165 | "command": "goto_method", 166 | "args": { 167 | "method": "-1" 168 | }, 169 | "context": [ 170 | {"key": "setting.sublime_enhanced_keybindings", "operator": "equal", "operand": true} 171 | ] 172 | }, 173 | 174 | { 175 | "keys": ["alt+ctrl+n"], 176 | "command": "goto_method", 177 | "args": { 178 | "method": "current", 179 | "position": "swap" 180 | }, 181 | "context": [ 182 | {"key": "setting.sublime_enhanced_keybindings", "operator": "equal", "operand": true} 183 | ] 184 | }, 185 | 186 | { 187 | "keys": ["ctrl+m", "ctrl+/"], 188 | "command": "goto_method", 189 | "args": { 190 | "method": "last" 191 | }, 192 | "context": [ 193 | {"key": "setting.sublime_enhanced_keybindings", "operator": "equal", "operand": true} 194 | ] 195 | }, 196 | 197 | { 198 | "keys": ["ctrl+m", "ctrl+f"], 199 | "command": "goto_method", 200 | "args": { 201 | "method": "0" 202 | }, 203 | "context": [ 204 | {"key": "setting.sublime_enhanced_keybindings", "operator": "equal", "operand": true} 205 | ] 206 | }, 207 | 208 | { 209 | "keys": ["ctrl+m", "ctrl+n"], 210 | "command": "create_method_space", 211 | "args": { 212 | "index": "current", 213 | "after": true 214 | }, 215 | "context": [ 216 | {"key": "setting.sublime_enhanced_keybindings", "operator": "equal", "operand": true} 217 | ] 218 | }, 219 | 220 | { 221 | "keys": ["ctrl+m", "ctrl+d"], 222 | "command": "delete_method", 223 | "args": { 224 | "method": "current" 225 | }, 226 | "context": [ 227 | {"key": "setting.sublime_enhanced_keybindings", "operator": "equal", "operand": true} 228 | ] 229 | }, 230 | 231 | { 232 | "keys": ["ctrl+m", "ctrl+c"], 233 | "command": "clone_method", 234 | "args": { 235 | "index": "current", 236 | "after": true 237 | }, 238 | "context": [ 239 | {"key": "setting.sublime_enhanced_keybindings", "operator": "equal", "operand": true} 240 | ] 241 | }, 242 | 243 | { 244 | "keys": ["ctrl+m", "ctrl+m"], 245 | "command": "insert_method_name_to_mark", 246 | "args": {}, 247 | "context": [ 248 | {"key": "setting.sublime_enhanced_keybindings", "operator": "equal", "operand": true} 249 | ] 250 | }, 251 | 252 | { 253 | "keys": ["ctrl+m", "ctrl+s"], 254 | "command": "select_methods", 255 | "args": { 256 | "methods": "current" 257 | }, 258 | "context": [ 259 | {"key": "setting.sublime_enhanced_keybindings", "operator": "equal", "operand": true} 260 | ] 261 | }, 262 | 263 | { 264 | "keys": ["ctrl+m", "s"], 265 | "command": "select_methods", 266 | "args": { 267 | "methods": "current", 268 | "body": true 269 | }, 270 | "context": [ 271 | {"key": "setting.sublime_enhanced_keybindings", "operator": "equal", "operand": true} 272 | ] 273 | }, 274 | 275 | { 276 | "keys": ["ctrl+m", "ctrl+q"], 277 | "command": "run_macro_file", 278 | "args": { 279 | "file": "res://Packages/Method/leave_only_current_test.sublime-macro" 280 | }, 281 | "context": [ 282 | {"key": "setting.sublime_enhanced_keybindings", "operator": "equal", "operand": true} 283 | ] 284 | }, 285 | 286 | { 287 | "keys": ["ctrl+m", "q"], 288 | "command": "run_macro_file", 289 | "args": { 290 | "file": "res://Packages/Method/uncomment_bookmarks.sublime-macro" 291 | }, 292 | "context": [ 293 | {"key": "setting.sublime_enhanced_keybindings", "operator": "equal", "operand": true} 294 | ] 295 | }, 296 | ] -------------------------------------------------------------------------------- /Method.sublime-commands: -------------------------------------------------------------------------------- 1 | [ 2 | 3 | { 4 | "caption": "Method: Create method before current", 5 | "command": "create_method", 6 | "args": { 7 | "index": "current" 8 | } 9 | }, 10 | 11 | { 12 | "caption": "Method: Create method after current", 13 | "command": "create_method", 14 | "args": { 15 | "index": "current", 16 | "after": true 17 | } 18 | }, 19 | 20 | { 21 | "caption": "Method: Create method after current", 22 | "command": "create_method", 23 | "args": { 24 | "index": "current", 25 | "after": true 26 | } 27 | }, 28 | 29 | { 30 | "caption": "Method: Create method after first", 31 | "command": "create_method", 32 | "args": { 33 | "index": 1 34 | } 35 | }, 36 | 37 | { 38 | "caption": "Method: Create protected method", 39 | "command": "create_method", 40 | "args": { 41 | "index": "protected" 42 | } 43 | }, 44 | 45 | { 46 | "caption": "Method: Create private method", 47 | "command": "create_method", 48 | "args": { 49 | "index": "private" 50 | } 51 | }, 52 | 53 | { 54 | "caption": "Method: Create method after last", 55 | "command": "create_method", 56 | "args": { 57 | "index": "last", 58 | "after": true 59 | } 60 | }, 61 | 62 | { 63 | "caption": "Method: Move method after first", 64 | "command": "move_method", 65 | "args": { 66 | "index": 0, 67 | "after": true, 68 | } 69 | }, 70 | 71 | { 72 | "caption": "Method: Move method to protected", 73 | "command": "move_method", 74 | "args": { 75 | "index": "protected" 76 | } 77 | }, 78 | 79 | { 80 | "caption": "Method: Move method to private", 81 | "command": "move_method", 82 | "args": { 83 | "index": "private" 84 | } 85 | }, 86 | 87 | { 88 | "caption": "Method: Move method to last", 89 | "command": "move_method", 90 | "args": { 91 | "index": "last", 92 | "after": true 93 | } 94 | }, 95 | 96 | { 97 | "caption": "Method: Move method up", 98 | "command": "move_method", 99 | "args": { 100 | "index": "-1" 101 | } 102 | }, 103 | 104 | { 105 | "caption": "Method: Move method down", 106 | "command": "move_method", 107 | "args": { 108 | "index": "+1", 109 | "after": true 110 | } 111 | }, 112 | 113 | { 114 | "caption": "Method: Go to next method", 115 | "command": "goto_method", 116 | "args": { 117 | "method": "+1" 118 | } 119 | }, 120 | 121 | { 122 | "caption": "Method: Go to previous method", 123 | "command": "goto_method", 124 | "args": { 125 | "method": "-1" 126 | } 127 | }, 128 | 129 | { 130 | "caption": "Method: Swap method start/end", 131 | "command": "goto_method", 132 | "args": { 133 | "method": "current", 134 | "position": "swap" 135 | } 136 | }, 137 | 138 | { 139 | "caption": "Method: Go to last method", 140 | "command": "goto_method", 141 | "args": { 142 | "method": "last" 143 | } 144 | }, 145 | 146 | { 147 | "caption": "Method: Go to first method", 148 | "command": "goto_method", 149 | "args": { 150 | "method": "0" 151 | } 152 | }, 153 | 154 | { 155 | "caption": "Method: Create method space", 156 | "command": "create_method_space", 157 | "args": { 158 | "index": "current", 159 | "after": true 160 | } 161 | }, 162 | 163 | { 164 | "caption": "Method: Delete method", 165 | "command": "delete_method", 166 | "args": { 167 | "method": "current" 168 | } 169 | }, 170 | 171 | { 172 | "caption": "Method: Clone method", 173 | "command": "clone_method", 174 | "args": { 175 | "index": "current", 176 | "after": true 177 | } 178 | }, 179 | 180 | { 181 | "caption": "Method: Insert method name to mark", 182 | "command": "insert_method_name_to_mark", 183 | "args": {} 184 | }, 185 | 186 | { 187 | "caption": "Method: Select current method", 188 | "command": "select_methods", 189 | "args": { 190 | "methods": "current" 191 | } 192 | }, 193 | 194 | { 195 | "caption": "Method: Select current method body", 196 | "command": "select_methods", 197 | "args": { 198 | "methods": "current", 199 | "body": true 200 | } 201 | }, 202 | 203 | { 204 | "caption": "Method: Comment all except current", 205 | "command": "run_macro_file", 206 | "args": 207 | { 208 | "file": "res://Packages/Method/leave_only_current_test.sublime-macro" 209 | } 210 | }, 211 | 212 | { 213 | "caption": "Method: Uncomment all", 214 | "command": "run_macro_file", 215 | "args": 216 | { 217 | "file": "res://Packages/Method/uncomment_bookmarks.sublime-macro" 218 | } 219 | }, 220 | ] -------------------------------------------------------------------------------- /commands.py: -------------------------------------------------------------------------------- 1 | import sublime 2 | import sublime_plugin 3 | import re 4 | 5 | from Method import method as parser 6 | 7 | try: 8 | from Statement import statement 9 | from Expression import expression 10 | from LocalVariable import local_variable 11 | except ImportError as error: 12 | sublime.error_message("Dependency import failed; please read readme for " + 13 | "Method plugin for installation instructions; to disable this " + 14 | "message remove this plugin; message: " + str(error)) 15 | raise error 16 | 17 | class MethodBase(sublime_plugin.TextCommand): 18 | 19 | def _get_language(self): 20 | if len(self.view.sel()) == 0: 21 | return None 22 | 23 | sel = self.view.sel()[0] 24 | 25 | match = re.search(r'source\.(\w+)', self.view.scope_name(sel.a)) 26 | if match == None: 27 | return None 28 | 29 | return match.group(1) 30 | 31 | def _get_methods(self): 32 | methods = parser.extract_methods(self.view) 33 | return methods 34 | 35 | def _get_method_regions(self, methods, index): 36 | return parser.get_regions(self.view, methods[index]) 37 | 38 | def _get_insert_info(self, region, target, after): 39 | text = self.view.substr(region) 40 | shift = [self.view.sel()[0].a - region.a, self.view.sel()[0].b - region.a] 41 | 42 | if after: 43 | text = "\n\n" + text 44 | point = target.b 45 | shift[0] += 2 46 | shift[1] += 2 47 | else: 48 | text += "\n\n" 49 | point = target.a 50 | 51 | return text, shift, point 52 | 53 | def _save_regions(self): 54 | self.view.erase_regions('Method') 55 | regions = [] 56 | for sel in self.view.sel(): 57 | regions.append(sublime.Region(sel.a, sel.b)) 58 | self.view.add_regions('Method', regions, 'method', '') 59 | 60 | def _restore_regions(self): 61 | self.view.sel().clear() 62 | regions = [] 63 | for region in self.view.get_regions('Method'): 64 | regions.append(sublime.Region(region.a, region.b)) 65 | self.view.sel().add_all(regions) 66 | 67 | def _get_cursor_position(self, method_info, after): 68 | if after: 69 | position = method_info["end"] 70 | else: 71 | position = method_info["start"] 72 | 73 | selection = sublime.Region(position, position) 74 | return selection 75 | 76 | def _set_cursor_position(self, method_info, after): 77 | selection = self._get_cursor_position(method_info, after) 78 | self.view.sel().clear() 79 | self.view.sel().add(selection) 80 | 81 | def _get_name_position(self, method_info): 82 | start = method_info["start"] 83 | text = self.view.substr(sublime.Region(start, start + 255)) 84 | name_start = start + text.index(method_info["name"]) 85 | name_end = name_start + len(method_info["name"]) 86 | return name_start, name_end 87 | 88 | def _insert_method_space(self, after): 89 | self.view.run_command('insert', {'characters': '\n\n'}) 90 | if not after: 91 | self.view.run_command('move', {'by': 'lines', 'forward': False}) 92 | self.view.run_command('move', {'by': 'lines', 'forward': False}) 93 | 94 | def _insert_method(self, edit, indent, snippet): 95 | selection = self.view.sel()[0] 96 | line = self.view.line(selection.b) 97 | indent_value = self._get_indent(indent) 98 | 99 | self.view.replace(edit, sublime.Region(line.a, selection.b), indent_value) 100 | self.view.run_command('insert_snippet', {'contents': snippet}) 101 | 102 | def _get_indent(self, indent): 103 | if self.view.settings().get('translate_tabs_to_spaces', False): 104 | tab = ' ' 105 | else: 106 | tab = "\t" 107 | 108 | return tab * indent 109 | 110 | def _prepare_index(self, methods, index): 111 | if index == None: 112 | return [] 113 | 114 | result = [] 115 | if isinstance(index, list): 116 | for index_item in index: 117 | result += self._prepare_index(methods, index_item) 118 | return result 119 | 120 | current = self._get_current_index(methods) 121 | 122 | match = None 123 | if isinstance(index, str): 124 | match = re.match(r"^(\+|\-|)(\d+)$", index) 125 | 126 | if current != None and match != None: 127 | if match.group(1) == '+': 128 | index = current + int(match.group(2)) 129 | if index > len(methods) - 1: 130 | index = len(methods) - 1 131 | elif match.group(1) == '-': 132 | index = current - int(match.group(2)) 133 | if index < 0: 134 | index = 0 135 | else: 136 | index = int(match.group(2)) 137 | 138 | result = [index] 139 | 140 | elif isinstance(index, str) and index[0] == '/': 141 | regexp = index[1 : - 1] 142 | index = None 143 | for method_index, method in enumerate(methods): 144 | if re.search(regexp, method["name"]): 145 | result.append(method_index) 146 | 147 | elif isinstance(index, str) and index[0] == ':': 148 | name = index[1 :] 149 | index = None 150 | for method_index, method in enumerate(methods): 151 | if name == method["name"]: 152 | index = method_index 153 | indexes.append(index) 154 | break 155 | 156 | elif index == 'current': 157 | result = [current] 158 | 159 | elif index == 'private': 160 | index = None 161 | for method_index, method in enumerate(methods): 162 | if method['privacy'] == 'private': 163 | result.append(method_index) 164 | 165 | elif index == 'last_private': 166 | index = None 167 | for method_index, method in reversed(enumerate(methods)): 168 | if method['privacy'] == 'private': 169 | result.append(method_index) 170 | 171 | elif index == 'protected': 172 | index = None 173 | for method_index, method in enumerate(methods): 174 | if method['privacy'] == 'protected': 175 | result.append(method_index) 176 | 177 | elif index == 'last_protected': 178 | index = None 179 | for method_index, method in reversed(enumerate(methods)): 180 | if method['privacy'] == 'protected': 181 | result.append(method_index) 182 | 183 | elif index == 'last': 184 | result = [len(methods) - 1] 185 | 186 | elif isinstance(index, int): 187 | result = [index] 188 | 189 | return result 190 | 191 | def _get_current_index(self, methods): 192 | cursor = self.view.sel()[0].b 193 | index = None 194 | 195 | max_cursor = 0 196 | for method_index, method in enumerate(methods): 197 | if cursor <= method["end"] and cursor > max_cursor: 198 | max_cursor = method["end"] 199 | index = method_index 200 | 201 | if index == None: 202 | index = len(methods) - 1 203 | 204 | return index 205 | 206 | def _get_definition(self, name, args, body, result, snippet): 207 | info = self._get_snippet_args(name, args, body, result) 208 | if info == None: 209 | return None 210 | 211 | name, args, body, result = info 212 | 213 | snippet = self._get_snippet_content(snippet) 214 | if snippet == None: 215 | return None 216 | 217 | snippet = self._set_args_to_snippet(snippet, name, args, body, result) 218 | return snippet 219 | 220 | def _get_snippet_content(self, snippet): 221 | language = self._get_language() 222 | if language == None: 223 | return None 224 | 225 | return parser.get_method_snippet(language, snippet) 226 | 227 | def _get_snippet_args(self, name, args, body, result): 228 | definition_info = self._get_definition_info() 229 | if definition_info == None: 230 | return 231 | 232 | definition_type, definition_region = definition_info 233 | if definition_type == 'name': 234 | if definition_region != None: 235 | new_name, new_args = self._extract_name(definition_region) 236 | else: 237 | new_name, new_args = None, [''] 238 | 239 | new_body, new_result = None, None 240 | else: 241 | new_body, new_args, new_result = self._extract_body(definition_region) 242 | new_name = None 243 | 244 | if name == None: 245 | name = new_name 246 | 247 | if args == None: 248 | args = new_args 249 | 250 | if body == None: 251 | body = new_body 252 | 253 | if result == None: 254 | result = new_result 255 | 256 | # fucking self 257 | scope_name = self.view.scope_name(self.view.sel()[0].a) 258 | if 'self' in args and 'python' in scope_name: 259 | args.remove('self') 260 | 261 | return name, args, body, result 262 | 263 | def _set_args_to_snippet(self, snippet, name, args, body, result): 264 | index = 1 265 | 266 | snippet = snippet.replace('$name', (name or '') + '$' + str(index)) 267 | index += 1 268 | 269 | args_value = [] 270 | for arg in args: 271 | arg = self._escape_snippet_value(arg) 272 | args_value.append('${' + str(index) + ':' + arg + '}') 273 | index += 1 274 | 275 | snippet = snippet.replace('$args', ', '.join(args_value)) 276 | 277 | if body != None: 278 | body = self._escape_snippet_value(body) 279 | if result != None and len(result) != 0: 280 | result_args = [] 281 | for result_arg in result: 282 | result_arg = self._escape_snippet_value(result_arg) 283 | result_args.append('${' + str(index) + ':' + result_arg + '}') 284 | index += 1 285 | 286 | body += '$' + str(index) + "\n\nreturn " + ', '.join(result_args) 287 | index += 1 288 | 289 | body_indent = re.search(r'\n(\s*)\$body', snippet) 290 | if body_indent != None: 291 | body = re.sub('(\n)', '\\1' + body_indent.group(1), body) 292 | snippet = snippet.replace('$body', (body or '') + '$' + str(index)) 293 | index += 1 294 | 295 | return snippet 296 | 297 | def _escape_snippet_value(self, value): 298 | return( 299 | value. 300 | replace('\\', '\\\\'). 301 | replace('$', '\\$'). 302 | replace('{', '\\{'). 303 | replace('}', '\\}') 304 | ) 305 | 306 | def _extract_name(self, region): 307 | token_value = self.view.substr(sublime.Region(*region)) 308 | parethesis = re.search(r'\(', token_value) 309 | if parethesis == None: 310 | name, args = token_value, [] 311 | else: 312 | name = token_value[: parethesis.start(0)] 313 | args_point = region[0] + parethesis.end(0) 314 | args_tokens = statement.get_tokens(self.view, args_point) or [] 315 | args = [] 316 | for arg in args_tokens: 317 | args.append(self.view.substr(sublime.Region(*arg))) 318 | 319 | name_match = re.search(r'[\w\?\!]+$', name) 320 | if name_match != None: 321 | name = name_match.group(0) 322 | 323 | return name, args 324 | 325 | def _extract_body(self, region): 326 | variables = local_variable.find_variables(self.view, region[0], False) 327 | 328 | assignments = [] 329 | for assignment in local_variable.find_all_assignments(self.view, region[0]): 330 | assignments.append(assignment['variable']) 331 | 332 | inner, following = [], [] 333 | for variable in variables: 334 | if region[0] <= variable[0] and variable[1] <= region[1]: 335 | value = self.view.substr(sublime.Region(*variable)) 336 | inner.append(value) 337 | elif region[1] <= variable[0]: 338 | value = self.view.substr(sublime.Region(*variable)) 339 | following.append(value) 340 | 341 | preceding_assignments, inner_assignments = [], [] 342 | for assignment in assignments: 343 | if assignment[1] <= region[0]: 344 | value = self.view.substr(sublime.Region(*assignment)) 345 | if value not in preceding_assignments: 346 | preceding_assignments.append(value) 347 | elif region[0] <= assignment[0] and assignment[1] <= region[1]: 348 | value = self.view.substr(sublime.Region(*assignment)) 349 | if value not in inner_assignments: 350 | inner_assignments.append(value) 351 | 352 | body = self._extract_indented_body(region) 353 | args = self._get_list_intersection(preceding_assignments, inner) 354 | result = self._get_list_intersection(inner_assignments, following) 355 | 356 | return body, args, result 357 | 358 | def _get_list_intersection(self, list1, list2): 359 | result = [] 360 | for item in list1: 361 | if item in list2: 362 | result.append(item) 363 | return result 364 | 365 | def _get_definition_info(self): 366 | selection = self.view.sel()[0] 367 | if selection.empty(): 368 | token_info = statement.get_token(self.view, selection.b) 369 | token = None 370 | if token_info != None: 371 | _, token = token_info 372 | 373 | if token == None or '(' not in self.view.substr(sublime.Region(*token)): 374 | token = statement.get_parent_token(self.view, selection.b, r'\(') 375 | 376 | if token == None: 377 | return 'name', None 378 | 379 | return 'name', token 380 | else: 381 | statement_1 = statement.get_statement(self.view, selection.begin()) 382 | statement_2 = statement.get_statement(self.view, selection.end()) 383 | 384 | if statement_1 == None or statement_2 == None: 385 | return None 386 | if statement_1 != statement_2 or expression.find_match(self.view, 387 | statement_1[0], r'\{', {'range': statement_1, 'string': False}) != None: 388 | return 'body', [statement_1[0], statement_2[1]] 389 | else: 390 | return 'name', statement_1 391 | 392 | def _extract_method_definition(self, cursor): 393 | _, token = statement.get_token(self.view, self.view.sel()[0].b) 394 | if token == None: 395 | return None 396 | 397 | if self.view.substr(sublime.Region(token[1] - 1, token[1])) != ')': 398 | token = statement.get_parent_token(self.view, cursor, r'\(') 399 | if token == None: 400 | return None 401 | 402 | return self.view.substr(sublime.Region(*token)) 403 | 404 | def _prepare_name(self, selection): 405 | return re.sub(r'^(self|\$?this)(\.|->)', '', selection) 406 | 407 | # this method copied from SnippetCaller _get_indented_region 408 | def _extract_indented_body(self, region): 409 | sel = sublime.Region(*region) 410 | 411 | region = sublime.Region(self.view.line(sel.begin()).a, sel.end()) 412 | text = re.sub(r'^([\n\s]*)\n', '', self.view.substr(region)) 413 | original_text = re.sub(r'^([\n\s]*)\n', '', self.view.substr(sel)) 414 | 415 | ignore_first_line = False 416 | if text.strip() != original_text.strip(): 417 | text = original_text 418 | ignore_first_line = True 419 | 420 | lines = text.split("\n") 421 | min = None 422 | source_indentation = '' 423 | for index, line in enumerate(lines): 424 | if ignore_first_line and index == 0: 425 | continue 426 | 427 | match = re.search(r'^(\s*)\S', line) 428 | 429 | if match == None: 430 | continue 431 | 432 | if min == None or min > len(match.group(1)): 433 | min = len(match.group(1)) 434 | source_indentation = match.group(1) 435 | 436 | result = re.sub(r'(^|\n)' + source_indentation, '\\1', text) 437 | result = result.rstrip() 438 | 439 | return result 440 | 441 | class SelectMethods(MethodBase): 442 | def run(self, edit, methods = 'current', excepts = None, body = False): 443 | current_methods = self._get_methods() 444 | 445 | methods_indexes = self._prepare_index(current_methods, methods) 446 | excepts_indexes = self._prepare_index(current_methods, excepts) 447 | 448 | self.view.sel().clear() 449 | for index in methods_indexes: 450 | if index in excepts_indexes: 451 | continue 452 | 453 | method = current_methods[index] 454 | 455 | if body: 456 | start, end = method['body_start'], method['body_end'] 457 | 458 | else: 459 | start, end = method["start"], method["end"] 460 | 461 | region = sublime.Region(start, end) 462 | if not body: 463 | region = self.view.line(region) 464 | 465 | self.view.sel().add(region) 466 | 467 | class GotoMethod(MethodBase): 468 | def run(self, edit, method = 'current', position = None): 469 | methods = self._get_methods() 470 | method = self._prepare_index(methods, method)[0] 471 | info = methods[method] 472 | 473 | cursor = info["start"] 474 | region = sublime.Region(cursor, self.view.size()) 475 | cursor += self.view.substr(region).index(info["name"]) + len(info["name"]) 476 | if position == 'swap': 477 | if self.view.sel()[0].b == cursor: 478 | cursor = info["end"] 479 | elif position != None: 480 | cursor = info[position] 481 | 482 | self.view.sel().clear() 483 | self.view.sel().add(sublime.Region(cursor, cursor)) 484 | self.view.show(sublime.Region(cursor, cursor)) 485 | 486 | class CloneMethod(MethodBase): 487 | def run(self, edit, method = 'current', index = 0, after = False): 488 | methods = self._get_methods() 489 | method = self._prepare_index(methods, method)[0] 490 | index = self._prepare_index(methods, index)[0] 491 | 492 | is_clone_invalid = ( 493 | (index < 0 or index > len(methods) - 1) 494 | ) 495 | 496 | if is_clone_invalid: 497 | return 498 | 499 | region, _, _ = self._get_method_regions(methods, method) 500 | target, _, _ = self._get_method_regions(methods, index) 501 | 502 | text, shift, point = self._get_insert_info(region, target, after) 503 | 504 | self.view.insert(edit, point, text) 505 | self.view.sel().clear() 506 | self.view.sel().add(sublime.Region(point + shift[0], point + shift[1])) 507 | 508 | class MoveMethod(MethodBase): 509 | def run(self, edit, method = 'current', index = 0, after = False): 510 | methods = self._get_methods() 511 | method = self._prepare_index(methods, method)[0] 512 | index = self._prepare_index(methods, index)[0] 513 | 514 | is_move_invalid = ( 515 | (method == index and after == True) or 516 | (index < 0 or index > len(methods) - 1) 517 | ) 518 | 519 | if is_move_invalid: 520 | return 521 | 522 | old, old_delete, lines = self._get_method_regions(methods, method) 523 | text = self.view.substr(old) 524 | shift = [self.view.sel()[0].a - old.a, self.view.sel()[0].b - old.a] 525 | 526 | self.view.replace(edit, old_delete, lines) 527 | methods = self._get_methods() 528 | 529 | if method < index: 530 | index -= 1 531 | 532 | new, _, _ = self._get_method_regions(methods, index) 533 | 534 | if after: 535 | text = "\n\n" + text 536 | point = new.b 537 | shift[0] += 2 538 | shift[1] += 2 539 | else: 540 | text += "\n\n" 541 | point = new.a 542 | 543 | self.view.insert(edit, point, text) 544 | self.view.sel().clear() 545 | self.view.sel().add(sublime.Region(point + shift[0], point + shift[1])) 546 | 547 | class DeleteMethod(MethodBase): 548 | def run(self, edit, method = 'current'): 549 | methods = self._get_methods() 550 | method = self._prepare_index(methods, method)[0] 551 | _, region, lines = self._get_method_regions(methods, method) 552 | self.view.replace(edit, region, lines) 553 | 554 | class InsertMethodNameToMark(MethodBase): 555 | def run(self, edit, method = 'current', snippets = []): 556 | methods = self._get_methods() 557 | method_index = self._prepare_index(methods, method)[0] 558 | 559 | snippet = self._get_snippet(snippets, methods[method_index]) 560 | 561 | self.view.run_command('goto_named_mark', {'name': 'method'}) 562 | self.view.run_command('insert_snippet', {'contents': snippet}) 563 | 564 | def _get_snippet(self, snippets, method): 565 | result_args, is_regular_snippet = self._get_result_args(method) 566 | snippet = self._get_snippet_value(snippets, is_regular_snippet) 567 | 568 | snippet_index = 1 569 | snippet_index, result_args_str = self._prepare_result_args(snippet_index, 570 | result_args, is_regular_snippet) 571 | 572 | args_prepared = self._get_args(method, snippet_index) 573 | 574 | snippet = (snippet. 575 | replace('${result}', result_args_str). 576 | replace('$name', method['name']). 577 | replace('$args', ', '.join(args_prepared))) 578 | 579 | return snippet 580 | 581 | def _get_args(self, method, snippet_index): 582 | match_options = { 583 | 'range': [method['start'], method['end']], 584 | 'nesting': True, 585 | } 586 | 587 | args_point = expression.find_match(self.view, method['start'], r'(?:\()', 588 | match_options) 589 | 590 | args = [] 591 | if args_point != None: 592 | tokens_point = method['start'] + args_point.end(0) 593 | tokens = statement.get_tokens(self.view, tokens_point) 594 | for token in tokens: 595 | args.append(self.view.substr(sublime.Region(*token))) 596 | 597 | # fucking self 598 | if 'python' in self.view.scope_name(method['start']) and 'self' in args: 599 | args.remove('self') 600 | 601 | args_prepared = [] 602 | for arg in args: 603 | snippet_index += 1 604 | args_prepared.append('${' + str(snippet_index) + ':' + 605 | re.search(r'^\S*', arg).group(0) + '}') 606 | 607 | return args_prepared 608 | 609 | def _prepare_result_args(self, snippet_index, result_args, is_regular): 610 | result_args_prepared = [] 611 | if result_args != None: 612 | for arg in result_args: 613 | arg_value = self.view.substr(sublime.Region(*arg)) 614 | snippet_index += 1 615 | result_args_prepared.append('${' + str(snippet_index) + ':' + 616 | self._escape_snippet_value(arg_value) + '}') 617 | 618 | result_args_str = ', '.join(result_args_prepared) 619 | if len(result_args_str) > 0 and is_regular: 620 | result_args_str += ' = ' 621 | 622 | return snippet_index, result_args_str 623 | 624 | def _get_snippet_value(self, snippets, is_regular_snippet): 625 | if len(snippets) != 0: 626 | if is_regular_snippet: 627 | snippet_file = snippets[0] 628 | else: 629 | snippet_file = snippets[1] 630 | 631 | snippet = parser.get_method_insert_snippet(self._get_language(), None, 632 | snippet_file) 633 | else: 634 | snippet = parser.get_method_insert_snippet(self._get_language(), 635 | not is_regular_snippet) 636 | 637 | return snippet 638 | 639 | def _get_result_args(self, method): 640 | returns = expression.find_matches(self.view, method['body_start'], 641 | r'(?:\n|^).*?return', {'range': [method['body_start'], 642 | method['body_end']], 'nesting': True}) 643 | 644 | null, result_args = None, None 645 | nulls = ['None', 'null', 'nil', 'undefined'] 646 | for return_match in returns: 647 | tokens = statement.get_tokens(self.view, method['body_start'] + 648 | return_match.end(0)) 649 | 650 | first_token = self.view.substr(sublime.Region(*tokens[0])) 651 | if len(tokens) == 1 and first_token in nulls: 652 | null = tokens[0] 653 | else: 654 | result_args = tokens 655 | 656 | is_regular_snippet = ( 657 | null == None or 658 | result_args == None or 659 | len(result_args) <= 1 660 | ) 661 | 662 | return result_args, is_regular_snippet 663 | 664 | class CreateMethodSpace(MethodBase): 665 | def run(self, edit, index = 0, after = False): 666 | methods = self._get_methods() 667 | index = self._prepare_index(methods, index)[0] 668 | self._set_cursor_position(methods[index], after) 669 | self._insert_method_space(after) 670 | 671 | class CreateMethod(MethodBase): 672 | def run(self, edit, 673 | index = 0, 674 | after = False, 675 | restore = False, 676 | name = None, 677 | args = None, 678 | body = None, 679 | result = None, 680 | snippet = None, 681 | cursor = '$auto', 682 | delete = '$auto', 683 | mark = True, 684 | ): 685 | if restore: 686 | self._save_regions() 687 | 688 | methods = self._get_methods() 689 | index = self._prepare_index(methods, index)[0] 690 | method_info = methods[index] 691 | indent = self._get_method_indent(method_info) 692 | 693 | snippet = self._get_definition(name, args, body, result, snippet) 694 | if snippet == None: 695 | raise Exception('Snippet for method not found') 696 | 697 | if mark and not restore: 698 | self.view.run_command('set_named_mark', {'name': 'method', 'icon': ''}) 699 | 700 | if delete: 701 | self.view.erase_regions('method_delete') 702 | self.view.add_regions('method_delete', [self.view.sel()[0]]) 703 | 704 | self._set_cursor_position(method_info, after) 705 | 706 | self._insert_method_space(after) 707 | self._insert_method(edit, indent, snippet) 708 | 709 | if restore: 710 | self._restore_regions() 711 | 712 | if mark and restore: 713 | self.view.run_command('set_named_mark', {'name': 'method', 'icon': ''}) 714 | 715 | deleted = self.view.get_regions('method_delete') 716 | if len(deleted) > 0: 717 | indent_match = re.search(r'(^|\n)([^\S\n]*)\S', self.view.substr(deleted[0])) 718 | if indent_match == None: 719 | indent = '' 720 | else: 721 | indent = indent_match.group(2) 722 | 723 | self.view.replace(edit, deleted[0], '') 724 | self.view.insert(edit, deleted[0].begin(), indent) 725 | 726 | def _get_method_indent(self, method): 727 | line = self.view.full_line(sublime.Region(method["start"], method["end"])) 728 | text = self.view.substr(line) 729 | match = re.match(r"^([ \t]*)[^\s]+", text) 730 | if match == None: 731 | return 0 732 | 733 | return len(match.group(1)) 734 | -------------------------------------------------------------------------------- /context.py: -------------------------------------------------------------------------------- 1 | import sublime 2 | import sublime_plugin 3 | 4 | from Context.base import Base 5 | from . import method 6 | 7 | class InMethodDefinition(Base): 8 | 9 | def on_query_context(self, view, *args): 10 | return self._check_sel('in_method_definition', self._check_point, view, 11 | *args) 12 | 13 | def _check_point(self, view, sel): 14 | info = method.extract_method(view, sel.a) 15 | if info == None: 16 | return False 17 | 18 | start = info['start'] 19 | value = view.substr(sublime.Region(start, info['body_start'])).strip() 20 | return start < sel.a and sel.b < start + len(value) 21 | 22 | class InMethod(Base): 23 | def on_query_context(self, view, *args): 24 | return self._check_sel('in_method', self._check_point, view, *args) 25 | 26 | def _check_point(self, view, sel): 27 | info = method.extract_method(view, sel.a) 28 | if info == None: 29 | return False 30 | 31 | return info['start'] < sel.a and sel.b < info['end'] 32 | 33 | class MethodName(Base): 34 | def on_query_context(self, view, *args): 35 | return self._check_sel('method_name', self._get_method_name, view, *args) 36 | 37 | def _get_method_name(self, view, sel): 38 | info = method.extract_method(view, sel.a) 39 | if info == None: 40 | return None 41 | 42 | return info['name'] -------------------------------------------------------------------------------- /demo/demo.py: -------------------------------------------------------------------------------- 1 | # some python code 2 | 3 | class MethodBase(sublime_plugin.TextCommand): 4 | 5 | def _process(self, result): 6 | # do stuff here... 7 | return result # method was moved 8 | 9 | def _prepare_index(self, methods, index): 10 | if index == None: 11 | return [] 12 | 13 | result = [] 14 | if isinstance(index, list): 15 | for index_item in index: 16 | result += self._prepare_index(methods, index_item) 17 | return result 18 | 19 | # done 20 | result = self._call(methods, index, result) 21 | 22 | # new method will be added 23 | result = self._process(result) 24 | 25 | return result 26 | 27 | def _call(self, methods, index, result): 28 | if current != None and match != None: 29 | if match.group(1) == '+': 30 | index = current + int(match.group(2)) 31 | if index > len(methods) - 1: 32 | index = len(methods) - 1 33 | 34 | result = [index] 35 | 36 | return result -------------------------------------------------------------------------------- /leave_only_current_test.sublime-macro: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "args": null, 4 | "command": "set_mark" 5 | }, 6 | { 7 | "args": { 8 | "excepts": ["current"], 9 | "methods": "/^(t|T)est/" 10 | }, 11 | "command": "select_methods" 12 | }, 13 | { 14 | "args": {"block": false}, 15 | "command": "toggle_comment" 16 | }, 17 | { 18 | "args": {"block": false}, 19 | "command": "toggle_bookmark" 20 | }, 21 | { 22 | "command": "next_bookmark", 23 | "args": {"name": "mark"}, 24 | }, 25 | { 26 | "command": "clear_bookmarks", 27 | "args": {"name": "mark"} 28 | } 29 | ] 30 | -------------------------------------------------------------------------------- /leave_only_current_test_go.sublime-macro: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "args": null, 4 | "command": "set_mark" 5 | }, 6 | { 7 | "args": { 8 | "excepts": ["current"], 9 | "methods": "/^Test/" 10 | }, 11 | "command": "select_methods" 12 | }, 13 | { 14 | "args": {"block": false}, 15 | "command": "toggle_comment" 16 | }, 17 | { 18 | "args": {"block": false}, 19 | "command": "toggle_bookmark" 20 | }, 21 | { 22 | "command": "next_bookmark", 23 | "args": {"name": "mark"}, 24 | }, 25 | { 26 | "command": "clear_bookmarks", 27 | "args": {"name": "mark"} 28 | } 29 | ] 30 | -------------------------------------------------------------------------------- /license.md: -------------------------------------------------------------------------------- 1 | # License 2 | 3 | The MIT License (MIT) 4 | 5 | Copyright (c) 2014 Leonid Shagabutdinov 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy 8 | of this software and associated documentation files (the "Software"), to deal 9 | in the Software without restriction, including without limitation the rights 10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | copies of the Software, and to permit persons to whom the Software is 12 | furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in all 15 | copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | SOFTWARE. -------------------------------------------------------------------------------- /method.py: -------------------------------------------------------------------------------- 1 | import sublime 2 | import sublime_plugin 3 | import re 4 | 5 | from xml.dom import minidom 6 | 7 | try: 8 | from Expression import expression 9 | except ImportError as error: 10 | sublime.error_message("Dependency import failed; please read readme for " + 11 | "Method plugin for installation instructions; to disable this " + 12 | "message remove this plugin; message: " + str(error)) 13 | raise error 14 | 15 | indented_languages = ['python', 'coffee', 'saas'] 16 | 17 | def extract_method(view, point = None): 18 | if point == None: 19 | point = view.sel()[0].begin() 20 | 21 | result = None 22 | for index, method in enumerate(extract_methods(view)): 23 | if point > method['start']: 24 | result = method 25 | 26 | return result 27 | 28 | def extract_methods(view): 29 | methods = [] 30 | text = view.substr(sublime.Region(0, view.size())) 31 | lines = text.split("\n") 32 | 33 | for index, word in enumerate(view.find_by_selector('entity.name.function')): 34 | start, body_start, privacy = _get_method_start(view, lines, word) 35 | end, body_end = _get_method_end(view, lines, start, body_start) 36 | 37 | methods.append({ 38 | 'index': index, 39 | 'name': view.substr(word), 40 | 'start': start, 41 | 'end': end, 42 | 'body_start': body_start, 43 | 'body_end': body_end, 44 | 'privacy': privacy, 45 | }) 46 | 47 | return methods 48 | 49 | def get_regions(view, method): 50 | start_line = view.line(method['start']) 51 | comment_point = start_line.a - 2 52 | if 'comment' in view.scope_name(comment_point): 53 | comment_start_point = view.extract_scope(comment_point).a 54 | start_line.a = view.line(comment_start_point).a 55 | 56 | region = sublime.Region(start_line.a, method['end']) 57 | delete = sublime.Region(region.a, region.b + 1) 58 | while True: 59 | if delete.a <= 0: 60 | break 61 | 62 | previous = view.line(delete.a - 1) 63 | if view.substr(previous).strip() == '': 64 | delete.a = previous.a 65 | else: 66 | break 67 | 68 | view_size = view.size() 69 | while True: 70 | if delete.b >= view_size: 71 | delete.b = view_size 72 | break 73 | 74 | next = view.line(delete.b) 75 | if view.substr(next).strip() == '': 76 | delete.b = next.b + 1 77 | else: 78 | break 79 | 80 | # delete.b += 1 81 | lines = '' 82 | 83 | # if index != 0 and index != len(methods) - 1: 84 | lines += "\n" 85 | 86 | return region, delete, lines 87 | 88 | def _get_method_start(view, lines, name_range): 89 | start_line, _ = view.rowcol(name_range.a) 90 | start_col = re.search(r'^(\s*)', lines[start_line]).end(1) 91 | 92 | start = view.text_point(start_line, start_col) 93 | body_start = name_range.b 94 | if '(' in lines[start_line]: 95 | body_start = _skip_parenthesis_or_return_args(view, body_start) 96 | 97 | # check { or : right after body_start 98 | body_start_match = re.search(r'^\s*[{:]', view.substr( 99 | sublime.Region(body_start, body_start + 64))) 100 | 101 | if body_start_match != None: 102 | body_start += body_start_match.end(0) 103 | 104 | # strip whitespaces 105 | body_start += re.search(r'^\s*', view.substr(sublime.Region(body_start, 106 | body_start + 64))).end(0) 107 | 108 | return start, body_start, _get_method_privacy(lines, start_line) 109 | 110 | def _skip_parenthesis_or_return_args(view, point): 111 | new_point = point 112 | while True: 113 | new_point = _skip_parenthesis(view, point) 114 | if new_point == point: 115 | break 116 | 117 | point = new_point 118 | 119 | if 'source.go' in view.scope_name(point): 120 | match = expression.find_match(view, point, r'{', 121 | {'range': [point, point + 128]}) 122 | if match != None: 123 | new_point += match.end(0) 124 | 125 | return new_point 126 | 127 | def _skip_parenthesis(view, point): 128 | if '(' not in view.substr(sublime.Region(point, view.line(point).b)): 129 | return point 130 | 131 | match = expression.find_match(view, point, r'\)', 132 | {'range': [point, point + 512], 'nesting': 'end'}) 133 | 134 | if match == None: 135 | return point 136 | 137 | return match.end(0) + point 138 | 139 | def _get_method_end(view, lines, start, body_start): 140 | empty = re.search(r'^\s*(\}|end)', view.substr(sublime.Region(body_start, 141 | body_start + 64))) 142 | 143 | if empty: 144 | return body_start + empty.end(0), body_start + empty.start(0) 145 | 146 | start_line, _ = view.rowcol(body_start) 147 | end_line = _method_method_end_line(view, lines, start_line) 148 | end = view.text_point(end_line, len(lines[end_line])) 149 | 150 | if _is_indented(view, start): 151 | body_end = end 152 | else: 153 | point = view.text_point(end_line, 0) 154 | end_line_range = view.line(point) 155 | body_end = end_line_range.a + re.search(r'^\s*', lines[end_line]).end(0) 156 | 157 | # stip body end 158 | body_end -= len(re.search(r'(\s*)$', view.substr(sublime.Region(body_end - 64, 159 | body_end))).group(0)) 160 | 161 | return end, body_end 162 | 163 | def _method_method_end_line(view, lines, start_line): 164 | previous_line_index, end_line = None, None 165 | source_indentation = len(re.match(r'^(\s*)', lines[start_line]).group(0)) 166 | 167 | for line_index in range(start_line, len(lines)): 168 | line = lines[line_index] 169 | if line.strip() == '': 170 | continue 171 | 172 | current_indentation = len(re.match(r'^(\s*)', line).group(0)) 173 | 174 | scope_name = view.scope_name(view.text_point(line_index, 0)) 175 | if 'string' in scope_name or 'comment' in scope_name: 176 | continue 177 | 178 | end_found = (current_indentation < source_indentation and 179 | not line.strip().startswith('rescue')) # ruby rescue hack 180 | 181 | if end_found: 182 | end_line_token = line.strip() 183 | if end_line_token == 'end' or end_line_token[0] == '}': 184 | end_line = line_index 185 | else: 186 | end_line = previous_line_index 187 | break 188 | 189 | previous_line_index = line_index 190 | 191 | if end_line == None: 192 | end_line = len(lines) - 1 193 | 194 | return end_line 195 | 196 | def _is_indented(view, point): 197 | scope = view.scope_name(point) 198 | for language in indented_languages: 199 | if language in scope: 200 | return True 201 | 202 | return False 203 | 204 | def _get_method_privacy(lines, line): 205 | if 'public' in lines[line]: 206 | return 'public' 207 | 208 | if 'protected' in lines[line]: 209 | return 'protected' 210 | 211 | if 'private' in lines[line]: 212 | return 'private' 213 | 214 | privacies = ['public', 'protected', 'private'] 215 | for index in reversed(range(0, line)): 216 | stripped = lines[index].strip() 217 | if stripped in privacies: 218 | return stripped 219 | 220 | return 'public' 221 | 222 | def get_method_insert_snippet(language, null = False, filename = None): 223 | if filename == None: 224 | if null: 225 | filename = language + '-method-call-null.sublime-snippet' 226 | else: 227 | filename = language + '-method-call.sublime-snippet' 228 | 229 | return _get_snippet_body(filename) 230 | 231 | def get_method_snippet(language, filename = None): 232 | if filename == None: 233 | filename = language + '-method.sublime-snippet' 234 | 235 | return _get_snippet_body(filename) 236 | 237 | def _get_snippet_body(filename): 238 | snippets = sublime.find_resources(filename) 239 | if len(snippets) == 0: 240 | raise Exception('Snippet "' + filename + '" not found') 241 | 242 | snippet = sublime.load_resource(snippets[0]) 243 | if snippet.strip() == '': 244 | return None 245 | 246 | xml = minidom.parseString(snippet).firstChild 247 | if xml == None: 248 | return None 249 | 250 | snippet = {} 251 | for node in xml.childNodes: 252 | if node.nodeType == node.ELEMENT_NODE: 253 | value_node = node.firstChild 254 | if value_node == None: 255 | continue 256 | 257 | if node.tagName == 'content': 258 | return value_node.data.strip() 259 | 260 | raise Exception('Snippet "' + name + '" is empty') 261 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # Sublime Method plugin 2 | 3 | The glorious plugin that allows (almost) language independent methods 4 | manipulation in file. 5 | 6 | ### Demo 7 | 8 | ![Demo](https://github.com/shagabutdinov/sublime-enhanced-demos/raw/master/method.gif "Demo") 9 | 10 | 11 | ### Installation 12 | 13 | This plugin is part of [sublime-enhanced](http://github.com/shagabutdinov/sublime-enhanced) 14 | plugin set. You can install sublime-enhanced and this plugin will be installed 15 | automatically. 16 | 17 | If you would like to install this package separately check "Installing packages 18 | separately" section of [sublime-enhanced](http://github.com/shagabutdinov/sublime-enhanced) 19 | package. 20 | 21 | 22 | ### WARNING 23 | 24 | This plugin does not works with multicursors. The reason is that I'm too lazy 25 | and the plugin is too complext to refactor it and add multicursors support. 26 | 27 | At least one method should be defined in current file before you can start using 28 | this plugin. At least one private or protected method should be defined if 29 | you want to work with private/protected methods. 30 | 31 | It relies heavely on source code indentation. If your file is poorly indented 32 | then this plugin will not work properly. 33 | 34 | E.g.: 35 | 36 | ``` 37 | # good 38 | def a() 39 | test() 40 | end 41 | 42 | # bad 43 | def a() 44 | test() 45 | end 46 | ``` 47 | 48 | There is default support for languages: ruby, python, php, js, coffee. If you 49 | want to provide other language supporting, you should create three files in 50 | "User" plugins directory: 51 | 52 | - [language]-method.sublime-snippet 53 | - [language]-method-call.sublime-snippet 54 | - [language]-method-call-null.sublime-snippet 55 | 56 | Where [language] is your language as it defined in sublime (to find out right 57 | name use "ctrl+u, ctrl+\" hotkey). 58 | 59 | See "snippets" directory for examples. You can also make pull request to make 60 | your language support available for everybody. 61 | 62 | ### Features 63 | 64 | 1. Create (extract) method - creates new method. It tries to detect method name, 65 | args, body and return value based on current cursor position. There is also 66 | bindings to show where to create method (in beginning of method list, in 67 | "private" section and etc.) 68 | 69 | 2. Move method - moves current method under cursor to new position (begin of 70 | methods list, to private) 71 | 72 | 3. Goto method - allows bind shortcuts to goto first/last method, first/last 73 | private method, next/previous method and method by name (e.g. "__init__") 74 | 75 | 4. Create method space - creates space for method so your preferred snippet can 76 | be executed here. Especeally good for defining tests. 77 | 78 | 5. Delete method - deletes current method. Especeally good when working with 79 | tests. 80 | 81 | 6. Clone method - clones current method. Especeally good when working with 82 | tests. 83 | 84 | 7. Insert method name to mark - inserts current method name, arguments and 85 | result to mark. 86 | 87 | 8. Select methods - select specified methods name or methods body. 88 | 89 | 9. Comment/uncomment all except current - usefull when you want to run only 90 | current test; hotkey is faster than specifying "--name test_my_feature" in 91 | command line. 92 | 93 | ### Usage 94 | 95 | Only few usecases displayed here. Please see "Commands" section to receive 96 | complete command list. 97 | 98 | ##### Create method (by name) 99 | 100 | ``` 101 | # before 102 | def a(a) 103 | b(a)| # <- cursor is here 104 | end 105 | 106 | # after 107 | def a(a) 108 | b(a) 109 | end 110 | 111 | def b|(a) # <- cursor is here 112 | 113 | end 114 | ``` 115 | 116 | ##### Create method (by body) 117 | 118 | ``` 119 | # before 120 | def a(a) 121 | {a = b(a) 122 | a = c(a)}| # <- selection is here 123 | d(a) 124 | end 125 | 126 | # after 127 | def a(a) 128 | 129 | end 130 | 131 | def |(a) # <- cursor is here 132 | a = b(a) 133 | a = c(a) 134 | return a 135 | end 136 | ``` 137 | 138 | ##### Move method down 139 | ``` 140 | # before 141 | def first() 142 | | # <- cursor is here 143 | end 144 | 145 | def second() 146 | 147 | end 148 | 149 | # after 150 | def second() 151 | 152 | end 153 | 154 | def first() 155 | | # <- cursor is here 156 | end 157 | ``` 158 | 159 | ### Commands 160 | 161 | | Description | Keyboard shortcut | Command palette | 162 | |------------------------------|-------------------|--------------------------------------| 163 | | Create method before current | ctrl+m, ctrl+, | Method: Create method before current | 164 | | Create method after current | ctrl+m, ctrl+. | Method: Create method after current | 165 | | Create method after current | ctrl+alt+shift+n | Method: Create method after current | 166 | | Create method after first | ctrl+m, ctrl+0 | Method: Create method after first | 167 | | Create protected method | ctrl+m, ctrl+o | Method: Create protected method | 168 | | Create private method | ctrl+m, ctrl+i | Method: Create private method | 169 | | Create method after last | ctrl+m, ctrl+l | Method: Create method after last | 170 | | Move method after first | ctrl+m, 0 | Method: Move method after first | 171 | | Move method to protected | ctrl+m, o | Method: Move method to protected | 172 | | Move method to private | ctrl+m, i | Method: Move method to private | 173 | | Move method to last | ctrl+m, l | Method: Move method to last | 174 | | Move method up | alt+- | Method: Move method up | 175 | | Move method down | alt+= | Method: Move method down | 176 | | Go to next method | alt+n | Method: Go to next method | 177 | | Go to previous method | alt+shift+n | Method: Go to previous method | 178 | | Swap method start/end | alt+ctrl+n | Method: Swap method start/end | 179 | | Go to last method | ctrl+m, ctrl+/ | Method: Go to last method | 180 | | Go to first method | ctrl+m, ctrl+f | Method: Go to first method | 181 | | Create method space | ctrl+m, ctrl+n | Method: Create method space | 182 | | Delete method | ctrl+m, ctrl+d | Method: Delete method | 183 | | Clone method | ctrl+m, ctrl+c | Method: Clone method | 184 | | Insert method name to mark | ctrl+m, ctrl+m | Method: Insert method name to mark | 185 | | Select current method | ctrl+m, ctrl+s | Method: Select current method | 186 | | Select current method body | ctrl+m, s | Method: Select current method body | 187 | | Comment all except current | ctrl+m, ctrl+q | Method: Comment all except current | 188 | | Uncomment all | ctrl+m, q | Method: Uncomment all | 189 | 190 | 191 | ### Dependencies 192 | 193 | * [Statement](https://github.com/shagabutdinov/sublime-statement) 194 | * [Expression](https://github.com/shagabutdinov/sublime-expression) 195 | * [LocalVariable](https://github.com/shagabutdinov/sublime-local-variable) -------------------------------------------------------------------------------- /snippets/coffee-method-call-null.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 7 | source.coffee 8 | Call coffee method (with null) 9 | -------------------------------------------------------------------------------- /snippets/coffee-method-call.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 5 | source.coffee 6 | Call coffee method 7 | -------------------------------------------------------------------------------- /snippets/coffee-method.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 4 | $body$0 5 | ]]> 6 | source.coffee 7 | Define method 8 | -------------------------------------------------------------------------------- /snippets/go-method-call-null.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 7 | source.go 8 | Call go method (with null) 9 | -------------------------------------------------------------------------------- /snippets/go-method-call.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 5 | source.go 6 | Call go method 7 | -------------------------------------------------------------------------------- /snippets/go-method.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 7 | source.go 8 | Define go method 9 | -------------------------------------------------------------------------------- /snippets/js-method-call-null.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 7 | source.js 8 | Call js method (with null) 9 | -------------------------------------------------------------------------------- /snippets/js-method-call.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 5 | source.js 6 | Call js method 7 | -------------------------------------------------------------------------------- /snippets/js-method.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 7 | source.js 8 | Define method 9 | -------------------------------------------------------------------------------- /snippets/php-method.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 7 | source.php 8 | Define method 9 | -------------------------------------------------------------------------------- /snippets/python-method-call-null.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 7 | source.python 8 | Call python method (with null) 9 | -------------------------------------------------------------------------------- /snippets/python-method-call.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 5 | source.python 6 | Call python method 7 | -------------------------------------------------------------------------------- /snippets/python-method.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 6 | source.python 7 | Define python method 8 | -------------------------------------------------------------------------------- /snippets/ruby-method-call-null.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 7 | source.ruby 8 | Call ruby method (null result) 9 | -------------------------------------------------------------------------------- /snippets/ruby-method-call.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 5 | source.ruby 6 | Call ruby method 7 | -------------------------------------------------------------------------------- /snippets/ruby-method.sublime-snippet: -------------------------------------------------------------------------------- 1 | 2 | 7 | source.ruby 8 | Define ruby method 9 | -------------------------------------------------------------------------------- /uncomment_bookmarks.sublime-macro: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "args": null, 4 | "command": "set_mark" 5 | }, 6 | { 7 | "args": null, 8 | "command": "select_all_bookmarks" 9 | }, 10 | { 11 | "args": {"block": false}, 12 | "command": "toggle_comment" 13 | }, 14 | { 15 | "args": {"block": false}, 16 | "command": "toggle_bookmark" 17 | }, 18 | { 19 | "command": "next_bookmark", 20 | "args": {"name": "mark"}, 21 | }, 22 | { 23 | "command": "clear_bookmarks", 24 | "args": {"name": "mark"} 25 | } 26 | ] 27 | --------------------------------------------------------------------------------