├── LICENSE ├── README.md ├── plugin └── partial.vim └── doc └── partial.txt /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Javier Blanco Gutiérrez 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # vim-partial 2 | 3 | Partial plugin is a tool developed to help you break down your code into partials. 4 | 5 | ## Usage 6 | Simply select some lines on Visual mode, hit `x`, enter the desired 7 | partial location and the plugin will place the appropriate replacement. 8 | 9 | Let me show you: 10 | 11 | ![vim-partial](https://cloud.githubusercontent.com/assets/24221/5893819/1eca7c62-a4f3-11e4-9df1-1ad372c1c604.gif) 12 | 13 | > **Note:** 14 | > Did you find this plugin useful? Please star it and 15 | > [share](https://twitter.com/home?status=%23vimpartial%20-%20easily%20extract%20partials%20from%20your%20code%20with%20this%20%23vim%20plugin%0A%0Ahttps://github.com/jbgutierrez/vim-partial) 16 | > with others. 17 | 18 | ## Configuration 19 | 20 | You can tweak the behavior of Partial by setting a few variables in your 21 | `vimrc` file. 22 | 23 | ### Default Mapping 24 | The default mapping to extract a partial is `x` in visual mode. 25 | The same mapping will dispose an existing partial in normal mode. 26 | 27 | You can easy map it to other keys. For example: 28 | 29 | ``` vim 30 | vmap p :PartialExtract 31 | nmap p :PartialDispose 32 | ``` 33 | 34 | ### g:loaded_partial 35 | Partial is loaded only once. Set this to 1 to force Partial to reload every 36 | time its file is sourced. 37 | 38 | ### g:partial_templates 39 | Common file extensions are supported (**Markup:** .dust, .erb, .haml, .slim - 40 | **Stylesheets:** .css, .less, .sass, .scss) and you can widen this list by 41 | declaring a dictionary like so: 42 | 43 | ``` vim 44 | let g:partial_templates = { 45 | \ 'ejs': '<%% include %s %%>', 46 | \ 'hbs': '{{> %s }}' 47 | \ } 48 | ``` 49 | 50 | ### g:partial_templates_roots 51 | Partial works with a list of usual roots for keeping your templates. 52 | If you happen to use an uncommon root folder you can extend this list 53 | like so: 54 | 55 | ``` vim 56 | let s:partial_templates_roots = [ 57 | \ 'stylus', 58 | \ 'tmpls' 59 | \ ] 60 | ``` 61 | 62 | ### g:partial_keep_position 63 | Cursor stays on the same position after replacement. Set this to 0 if you want 64 | to continue with the edition of the partial file. 65 | 66 | ### g:partial_use_splits 67 | New windows for partials are closed after being created. Set 68 | this to 1 if you want to keep the partial in a new window. 69 | 70 | ### g:partial_vertical_split 71 | Partial uses horizontal splits. Set this to 1 if you prefer vertical splits. 72 | 73 | ### g:partial_create_dirs 74 | Partial creates directories as required. Set this to 0 if you don't want 75 | Partial to create new directories. 76 | 77 | ## Implementation details 78 | 79 | After triggering `:PartialExtract` the editor will: 80 | 81 | * throw an error if the file type is not supported (you may want to expand this list!) 82 | * suggest a folder with the same name as the file you are working in (without extensions) 83 | * throw an error if the file exists (you can overcome this error by triggering `:PartialExtract!`) 84 | * ensure the file has the proper extension(s) and create intermediate directories as required 85 | * set partial path relative to the templates folder and dispose any preceding 86 | underscores on the partial name 87 | * save the partial content getting rid of unneeded leading spaces and tabs 88 | * make the replacement 89 | 90 | Partial tries to set `suffixesadd` and `includeexpr` on 91 | `BufEnter` to navigate to partials under the cursor with `gf`. 92 | 93 | ## Bugs 94 | 95 | Please report any bugs you may find on the GitHub [issue tracker](http://github.com/jbgutierrez/vim-partial/issues). 96 | 97 | ## Contributing 98 | 99 | Think you can make Partial better? Great!, contributions are always welcome. 100 | 101 | Fork the [project](http://github.com/jbgutierrez/partial.vim) on GitHub and send a pull request. 102 | 103 | ## Credits 104 | 105 | This isn't new. I've borrow the core idea from the following two plugins: 106 | 107 | * [vim-rails](https://github.com/tpope/vim-rails) - highly recommended 108 | * [rails-partial](https://github.com/wesf90/rails-partial) - sublime users 109 | 110 | ## License 111 | 112 | Partial is licensed under the MIT license. 113 | See http://opensource.org/licenses/MIT 114 | 115 | Happy hacking! 116 | -------------------------------------------------------------------------------- /plugin/partial.vim: -------------------------------------------------------------------------------- 1 | " ============================================================================= 2 | " File: plugin/partial.vim 3 | " Description: Makes creating partials in your code a breeze! 4 | " Author: Javier Blanco 5 | " ============================================================================= 6 | 7 | if ( exists('g:loaded_partial') && g:loaded_partial ) || v:version < 700 || &cp 8 | finish 9 | endif 10 | let g:loaded_partial = 1 11 | 12 | " Mappings {{{ 13 | 14 | if !hasmapto(':PartialExtract') 15 | vmap x :PartialExtract 16 | nmap x :PartialDispose 17 | endif 18 | 19 | " }}} 20 | 21 | " Functions {{{ 22 | 23 | function! s:error(str) 24 | echohl ErrorMsg 25 | echomsg a:str 26 | echohl None 27 | let v:errmsg = a:str 28 | endfunction 29 | 30 | function! s:debug(str) 31 | if exists("g:partial_debug") && g:partial_debug 32 | echohl Debug 33 | echomsg a:str 34 | echohl None 35 | endif 36 | endfunction 37 | 38 | function! s:sub(str,pat,rep) 39 | return substitute(a:str,'\v\C'.a:pat,a:rep,'') 40 | endfunction 41 | 42 | let s:templates = { 43 | \ 'css' : "@import url('%s');" , 44 | \ 'dust' : '{> "%s" /}' , 45 | \ 'erb' : "<%%= render '%s' %%>" , 46 | \ 'haml' : "= render '%s'" , 47 | \ 'html' : "<%%= render '%s' %%>" , 48 | \ 'less' : "@import '%s';" , 49 | \ 'sass' : "@import '%s'" , 50 | \ 'scss' : "@import '%s';" , 51 | \ 'slim' : "== render '%s'" 52 | \ } 53 | 54 | if exists("g:partial_templates") | call extend(s:templates, g:partial_templates) | endif 55 | 56 | let s:templates_roots = [ 57 | \ 'css', 58 | \ 'sass', 59 | \ 'styles', 60 | \ 'stylesheets', 61 | \ 'templates', 62 | \ 'views' 63 | \ ] 64 | if exists("g:partial_templates_roots") | call extend(s:templates_roots, g:partial_templates_roots) | endif 65 | let s:templates_roots_re = '\v(.*[\/])('.join(s:templates_roots, '|').')[\/]' 66 | 67 | let s:use_splits = exists("g:partial_use_splits") ? g:partial_use_splits : 0 68 | let s:keep_position = exists("g:partial_keep_position") ? g:partial_keep_position : 1 69 | let s:vertical_split = exists("g:partial_vertical_split") ? g:partial_vertical_split : 0 70 | let s:create_dirs = exists("g:partial_create_dirs") ? g:partial_create_dirs : 1 71 | 72 | function! s:get_template_context() 73 | let extension = expand('%:e') 74 | if !has_key(s:templates, extension) 75 | return s:error('Unsupported file type (see :help partial_templates)') 76 | endif 77 | let templates_root = expand('%:p:s?'.s:templates_roots_re.'.*?\1\2?') 78 | if templates_root == expand('%:p') 79 | return s:error("Destination path must be within a known root for templates (see :help PartialConfig_templates_root)") 80 | endif 81 | 82 | return [s:templates[extension], templates_root] 83 | endfunction 84 | 85 | function! s:partial_extract(bang) range abort 86 | let template_context = s:get_template_context() 87 | if empty(template_context) | return | endif 88 | let [template, templates_root] = template_context 89 | let filename = expand('%') 90 | let basename = expand('%:p:s?'.s:templates_roots_re.'(.*)?\3?:r:r') 91 | 92 | let partial_name = input('Partial name: ', basename, 'file') 93 | if partial_name == '' || partial_name == filename | return | endif 94 | 95 | let extensions = fnamemodify(filename, ':e:e') 96 | let partial_name = fnamemodify(partial_name, ':r:r').".".extensions 97 | 98 | if filereadable(partial_name) && !a:bang 99 | return s:error('E13: File exists') 100 | endif 101 | 102 | let folder = templates_root."/".fnamemodify(partial_name, ':h') 103 | if !isdirectory(folder) 104 | if s:create_dirs 105 | call mkdir(folder, 'p') 106 | else 107 | return s:error("Folder '".folder."' doesn't exists (see :help PartialConfig_create_dirs)") 108 | endif 109 | endif 110 | 111 | let first = a:firstline 112 | let last = a:lastline 113 | let range = first.",".last 114 | let spaces = matchstr(getline(first),'^\s*') 115 | let partial = fnamemodify(partial_name, ':r:r:s?'.s:templates_roots_re.'??:s?\v(.*)_([^/^.]+)[^/]*?\1\2?:s?\v\?/?g') 116 | 117 | let buf = @@ 118 | let winnr = winnr() 119 | let autoindent = &autoindent 120 | let splitright = &splitright 121 | let splitbelow = &splitbelow 122 | let &autoindent = 0 123 | if s:keep_position 124 | let &splitright = 1 125 | let &splitbelow = 1 126 | end 127 | 128 | let replacement = printf(template, partial) 129 | silent! exe range."yank" 130 | silent! exe "normal! :".first.",".last."change\".spaces.replacement."\.\" 131 | 132 | if s:vertical_split | vnew | else | new | end 133 | 134 | silent! put 135 | 0delete 136 | if spaces != "" 137 | silent! exe '%substitute/^'.spaces.'//' 138 | endif 139 | 140 | try 141 | silent! exe "w! ".templates_root."/".partial_name 142 | catch 143 | s:error('E80 Error while writing') 144 | endtry 145 | 146 | let &autoindent = autoindent 147 | let &splitright = splitright 148 | let &splitbelow = splitbelow 149 | if s:use_splits | exe winnr . "wincmd w" | else | close | endif 150 | let @@ = buf 151 | endfunction 152 | 153 | function! s:partial_dispose(bang) 154 | let [template, templates_root] = s:get_template_context() 155 | 156 | let filename = expand('%') 157 | let template = substitute(template, '%%', '%', 'g') 158 | let pat = '(\s*)'.substitute(template, '%s', '(.*)', '') 159 | let pat = escape(pat, '()') 160 | let matchlist = matchlist(getline('.'), pat) 161 | if len(matchlist) > 0 162 | let choice = a:bang 163 | if !choice 164 | let choice = confirm("Remove partial file?", "&Yes\n&No\n&Cancel") 165 | if choice == 0 | return | endif 166 | endif 167 | let extensions = fnamemodify(filename, ':e:e') 168 | let partial_name = matchlist[2].'.'.extensions 169 | delete 170 | let partial_path = templates_root."/".partial_name 171 | let lineno=line('.') 172 | for line in reverse(readfile(partial_path)) 173 | call append(lineno - 1, matchlist[1].line) 174 | endfor 175 | call cursor(lineno, col('.')) 176 | if choice == 1 | call delete(partial_path) | endif 177 | else 178 | return s:error("No partial found") 179 | endif 180 | endfunction 181 | 182 | "}}} 183 | 184 | " Commands {{{ 185 | 186 | command! -bang -range PartialExtract ,call partial_extract(0) 187 | command! -bang PartialDispose call partial_dispose(0) 188 | 189 | "}}} 190 | 191 | " Autocommands {{{ 192 | 193 | augroup partialPluginAuto 194 | autocmd! 195 | autocmd BufEnter * exe "setlocal suffixesadd=.".expand('%:e') 196 | autocmd BufEnter * if &includeexpr == '' | setlocal includeexpr=substitute(v:fname,'\\v([^\\^/]+)$','_\\1','') | end 197 | augroup END 198 | 199 | " }}} 200 | 201 | " vim:fen:fdm=marker:fmr={{{,}}}:fdl=0:fdc=1:ts=2:sw=2:sts=2 202 | -------------------------------------------------------------------------------- /doc/partial.txt: -------------------------------------------------------------------------------- 1 | *partial.txt* easily extract partials from your code 2 | 3 | 4 | ___ _ _ _ 5 | / _ \__ _ _ __| |_(_) __ _| | 6 | / /_)/ _` | '__| __| |/ _` | | 7 | / ___/ (_| | | | |_| | (_| | | 8 | \/ \__,_|_| \__|_|\__,_|_| 9 | 10 | Makes creating partials in your code a breeze! 11 | 12 | ============================================================================== 13 | CONTENTS *Partial-contents* 14 | 15 | 1. Usage ................................... |PartialUsage| 16 | 2. Configurations .......................... |PartialConfig| 17 | 2.1 Default Mapping .................... |PartialConfig_mapping| 18 | 2.2 loaded_partial ..................... |PartialConfig_debug| 19 | 2.3 partial_templates .................. |PartialConfig_templates| 20 | 2.4 partial_templates_roots ........... |PartialConfig_templates_root| 21 | 2.5 partial_keep_position .............. |PartialConfig_keep_position| 22 | 2.6 partial_use_splits ................. |PartialConfig_use_splits| 23 | 2.7 partial_vertical_split ............. |PartialConfig_vertical_split| 24 | 2.8 partial_create_dirs ................ |PartialConfig_create_dirs| 25 | 3. Implementation details................... |PartialModes| 26 | 4. Contributing ............................ |PartialContributing| 27 | 5. Bugs .................................... |PartialContributing| 28 | 6. Credits ................................. |PartialCredits| 29 | 7. Changelog ............................... |PartialChangelog| 30 | 9. License ................................. |PartialLicense| 31 | 32 | 33 | ============================================================================== 34 | 1. Usage *PartialUsage* 35 | 36 | Partial plugin is a tool developed to help you break down your code into 37 | partials. Simply select some lines on Visual mode, hit x, enter the 38 | desired partial location and the plugin will place the appropriate replacement. 39 | 40 | ============================================================================== 41 | 2. Configuration *PartialConfig* 42 | 43 | You can tweak the behavior of Partial by setting a few variables in your 44 | vimrc file. For example: > 45 | 46 | ------------------------------------------------------------------------------ 47 | 2.1 Default Mapping *PartialConfig_mapping* 48 | 49 | The default mapping to extract a partial is x in visual mode. 50 | The same mapping will dispose an existing partial in normal mode. 51 | 52 | You can easy map it to other keys. For example: 53 | 54 | vmap P :PartialExtract 55 | nmap P :PartialDispose 56 | 57 | ------------------------------------------------------------------------------ 58 | 2.2 g:loaded_partial *PartialConfig_loaded* 59 | 60 | Partial is loaded only once. Set this to 1 to force Partial to reload every 61 | time its file is sourced. 62 | 63 | ------------------------------------------------------------------------------ 64 | 2.3 g:partial_templates *PartialConfig_templates* 65 | 66 | Common file extensions are supported (Markup: .dust, .erb, .haml, .slim - 67 | Stylesheet: .css, .less, .sass, .scss) and you can widen this list by 68 | declaring a dictionary like so: 69 | 70 | let g:partial_templates = { 71 | \ 'ejs': '<% include %s %>', 72 | \ 'hbs': '{{> %s }}' 73 | \ } 74 | 75 | ------------------------------------------------------------------------------ 76 | 2.4 g:partial_templates_roots *PartialConfig_templates_root* 77 | 78 | Partial works with a list of usual roots for keeping your templates. 79 | If you happen to use an uncommon root folder you can extend this list 80 | like so: 81 | 82 | let s:partial_templates_roots = [ 83 | \ 'stylus', 84 | \ 'tmpls' 85 | \ ] 86 | 87 | ------------------------------------------------------------------------------ 88 | 2.5 g:partial_keep_position *PartialConfig_keep_position* 89 | 90 | Cursor stays on the same position after replacement. Set this to 0 if you want 91 | to continue with the edition of the partial file. 92 | 93 | ------------------------------------------------------------------------------ 94 | 2.6 g:partial_use_splits *PartialConfig_use_splits* 95 | 96 | New windows for partials are closed after being created. Set 97 | this to 1 if you want to keep the partial in a new window. 98 | 99 | ------------------------------------------------------------------------------ 100 | 2.7 g:partial_vertical_split *PartialConfig_vertical_split* 101 | 102 | Partial uses horizontal splits. Set this to 1 if you prefer vertical splits. 103 | 104 | ------------------------------------------------------------------------------ 105 | 2.8 g:partial_create_dirs *PartialConfig_create_dirs* 106 | 107 | Partial creates directories as required. Set this to 0 if you don't want 108 | Partial to create new directories. 109 | 110 | ============================================================================== 111 | 3. Implementation details *PartialModes* 112 | 113 | After triggering :PartialExtract the editor will: 114 | 115 | * throw an error if the file type is not supported 116 | (you may want to expand this list!) 117 | * suggest a folder with the same name as the file you are working in 118 | (without extensions) 119 | * throw an error if the file exists (you can overcome this error 120 | by triggering :PartialExtract!) 121 | * ensure the file has the proper extension(s) and create intermediate 122 | directories as required 123 | * set partial path relative to the templates folder and dispose any 124 | preceding underscores on the partial name 125 | * save the partial content getting rid of unneeded leading spaces and tabs 126 | * make the replacement 127 | 128 | Partial tries to set `suffixesadd` and `includeexpr` on 129 | `BufEnter` to navigate to partials under the cursor with `gf`. 130 | 131 | ============================================================================== 132 | 4. Bugs *PartialBugs* 133 | 134 | Please report any bugs you may find on the GitHub issue tracker: 135 | 136 | http://github.com/jbgutierrez/partial.vim/issues 137 | 138 | ============================================================================== 139 | 5. Contributing *PartialContributing* 140 | 141 | Think you can make Partial better? Great!, contributions are always welcome. 142 | 143 | Fork the project on GitHub and send a pull request. 144 | 145 | GitHub: http://github.com/jbgutierrez/partial.vim 146 | 147 | ============================================================================== 148 | 6. Changelog *PartialChangelog* 149 | 150 | v0.1.0 151 | * First working version 152 | 153 | ============================================================================== 154 | 7. Credits *PartialCredits* 155 | 156 | I've borrow the core idea from the following two plugins: 157 | 158 | * https://github.com/tpope/vim-rails - highly recommended 159 | * https://github.com/wesf90/rails-partial - sublime users 160 | 161 | ============================================================================== 162 | 8. License *PartialLicense* 163 | 164 | Partial is licensed under the MIT license. 165 | See http://opensource.org/licenses/MIT 166 | 167 | ============================================================================== 168 | 169 | 170 | vim:ts=4:et:ft=help: 171 | --------------------------------------------------------------------------------