at 15.09-beta 13 kB view raw
1{stdenv, vim, vimPlugins, vim_configurable, buildEnv, writeText, writeScriptBin}: 2 3/* 4 5USAGE EXAMPLE 6============= 7 8Install Vim like this eg using nixos option environment.systemPackages which will provide 9vim-with-plugins in PATH: 10 11 vim_configurable.customize { 12 name = "vim-with-plugins"; 13 14 # add custom .vimrc lines like this: 15 vimrcConfig.customRC = '' 16 set hidden 17 ''; 18 19 vimrcConfig.vam.knownPlugins = pkgs.vimPlugins; # optional 20 vimrcConfig.vam.pluginDictionaries = [ 21 # load always 22 { name = "youcompleteme"; } 23 { names = ["youcompleteme" "foo"]; } 24 25 # only load when opening a .php file 26 { name = "phpCompletion"; ft_regex = "^php\$"; } 27 { name = "phpCompletion"; filename_regex = "^.php\$"; } 28 29 # provide plugin which can be loaded manually: 30 { name = "phpCompletion"; tag = "lazy"; } 31 32 # full ducomentation at github.com/MarcWeber/vim-addon-manager 33 ]; 34 35 # there is a pathogen implementation as well, but its startup is slower and [VAM] has more feature 36 # vimrcConfig.pathogen.knownPlugins = vimPlugins; # optional 37 # vimrcConfig.pathogen.pluginNames = ["vim-addon-nix"]; 38 }; 39 40WHAT IS A VIM PLUGIN? 41===================== 42Typical plugin files: 43 44 plugin/P1.vim 45 autoload/P1.vim 46 ftplugin/xyz.vim 47 doc/plugin-documentation.txt (traditional documentation) 48 README(.md) (nowadays thanks to github) 49 50 51Vim offers the :h rtp setting which works for most plugins. Thus adding 52this to your .vimrc should make most plugins work: 53 54 set rtp+=~/.nix-profile/share/vim-plugins/youcompleteme 55 " or for p in ["youcompleteme"] | exec 'set rtp+=~/.nix-profile/share/vim-plugins/'.p | endfor 56 57which is what the [VAM]/pathogen solutions above basically do. 58 59Learn about about plugin Vim plugin mm managers at 60http://vim-wiki.mawercer.de/wiki/topic/vim%20plugin%20managment.html. 61 62The documentation can be accessed by Vim's :help command if it was tagged. 63See vimHelpTags sample code below. 64 65CONTRIBUTING AND CUSTOMIZING 66============================ 67The example file pkgs/misc/vim-plugins/default.nix provides both: 68* manually mantained plugins 69* plugins created by VAM's nix#ExportPluginsForNix implementation 70 71I highly recommend to lookup vim plugin attribute names at the [vim-pi] project 72 which is a database containing all plugins from 73vim.org and quite a lot of found at github and similar sources. vim-pi's documented purpose 74is to associate vim.org script ids to human readable names so that dependencies 75can be describe easily. 76 77How to find a name? 78 * http://vam.mawercer.de/ or VAM's 79 * grep vim-pi 80 * use VAM's completion or :AddonsInfo command 81 82It might happen than a plugin is not known by vim-pi yet. We encourage you to 83contribute to vim-pi so that plugins can be updated automatically. 84 85 86CREATING DERVITATIONS AUTOMATICALLY BY PLUGIN NAME 87================================================== 88Most convenient is to use a ~/.vim-scripts file putting a plugin name into each line 89as documented by [VAM]'s README.md 90It is the same format you pass to vimrcConfig.vam.pluginDictionaries from the 91usage example above. 92 93Then create a temp vim file and insert: 94 95 let opts = {} 96 let opts.path_to_nixpkgs = '/etc/nixos/nixpkgs' 97 let opts.cache_file = '/tmp/export-vim-plugin-for-nix-cache-file' 98 let opts.plugin_dictionaries = map(readfile("vim-plugins"), 'eval(v:val)') 99 " add more files 100 " let opts.plugin_dictionaries += map(.. other file ) 101 call nix#ExportPluginsForNix(opts) 102 103Then ":source %" it. 104 105nix#ExportPluginsForNix is provided by github.com/JagaJaga/vim-addon-vim2nix 106 107A buffer will open containing the plugin derivation lines as well list 108fitting the vimrcConfig.vam.pluginDictionaries option. 109 110Thus the most simple usage would be: 111 112 vim_with_plugins = 113 let vim = vim_configurable; 114 inherit (vimUtil.override {inherit vim}) rtpPath addRtp buildVimPlugin vimHelpTags; 115 vimPlugins = [ 116 # the derivation list from the buffer created by nix#ExportPluginsForNix 117 # don't set which will default to pkgs.vimPlugins 118 ]; 119 in vim.customize { 120 name = "vim-with-plugins"; 121 122 vimrcConfig.customRC = '' .. ''; 123 124 vimrcConfig.vam.knownPlugins = vimPlugins; 125 vimrcConfig.vam.pluginDictionaries = [ 126 # the plugin list form ~/.vim-scripts turned into nix format added to 127 # the buffer created by the nix#ExportPluginsForNix 128 ]; 129 } 130 131vim_with_plugins can be installed like any other application within Nix. 132 133[VAM] https://github.com/MarcWeber/vim-addon-manager 134[vim-pi] https://bitbucket.org/vimcommunity/vim-pi 135*/ 136 137 138let 139 inherit (stdenv) lib; 140 141 findDependenciesRecursively = {knownPlugins, names}: 142 143 let depsOf = name: (builtins.getAttr name knownPlugins).dependencies or []; 144 145 recurseNames = path: names: lib.concatMap (name: recurse ([name]++path)) names; 146 147 recurse = path: 148 let name = builtins.head path; 149 in if builtins.elem name (builtins.tail path) 150 then throw "recursive vim dependencies" 151 else [name] ++ recurseNames path (depsOf name); 152 153 in lib.uniqList { inputList = recurseNames [] names; }; 154 155 vimrcFile = { 156 vam ? null, 157 pathogen ? null, 158 customRC ? "" 159 }: 160 161 let 162 /* pathogen mostly can set &rtp at startup time. Its used very commonly. 163 */ 164 pathogenImpl = lib.optionalString (pathogen != null) 165 (let 166 knownPlugins = pathogen.knownPlugins or vimPlugins; 167 168 plugins = map (name: knownPlugins.${name}) (findDependenciesRecursively { inherit knownPlugins; names = pathogen.pluginNames; }); 169 170 pluginsEnv = buildEnv { 171 name = "pathogen-plugin-env"; 172 paths = map (x: "${x}/${vimPlugins.rtpPath}") plugins; 173 }; 174 in 175 '' 176 let &rtp.=(empty(&rtp)?"":',')."${vimPlugins.pathogen.rtp}" 177 execute pathogen#infect('${pluginsEnv}/{}') 178 ''); 179 180 /* 181 vim-addon-manager = VAM 182 183 * maps names to plugin location 184 185 * manipulates &rtp at startup time 186 or when Vim has been running for a while 187 188 * can activate plugins laziy (eg when loading a specific filetype) 189 190 * knows about vim plugin dependencies (addon-info.json files) 191 192 * still is minimalistic (only loads one file), the "check out" code it also 193 has only gets loaded when a plugin is requested which is not found on disk 194 yet 195 196 */ 197 vamImpl = lib.optionalString (vam != null) 198 (let 199 knownPlugins = vam.knownPlugins or vimPlugins; 200 201 toNames = x: 202 if builtins.isString x then [x] 203 else (lib.optional (x ? name) x.name) 204 ++ (x.names or []); 205 206 names = findDependenciesRecursively { inherit knownPlugins; names = lib.concatMap toNames vam.pluginDictionaries; }; 207 208 # Vim almost reads JSON, so eventually JSON support should be added to Nix 209 # TODO: proper quoting 210 toNix = x: 211 if (builtins.isString x) then "'${x}'" 212 else if builtins.isAttrs x && builtins ? out then toNix "${x}" # a derivation 213 else if builtins.isAttrs x then "{${lib.concatStringsSep ", " (lib.mapAttrsToList (n: v: "${toNix n}: ${toNix v}") x)}}" 214 else if builtins.isList x then "[${lib.concatMapStringsSep ", " toNix x}]" 215 else throw "turning ${lib.showVal x} into a VimL thing not implemented yet"; 216 217 in assert builtins.hasAttr "vim-addon-manager" knownPlugins; 218 '' 219 let g:nix_plugin_locations = {} 220 ${lib.concatMapStrings (name: '' 221 let g:nix_plugin_locations['${name}'] = "${knownPlugins.${name}.rtp}" 222 '') names} 223 let g:nix_plugin_locations['vim-addon-manager'] = "${knownPlugins."vim-addon-manager".rtp}" 224 225 let g:vim_addon_manager = {} 226 227 if exists('g:nix_plugin_locations') 228 " nix managed config 229 230 " override default function making VAM aware of plugin locations: 231 fun! NixPluginLocation(name) 232 let path = get(g:nix_plugin_locations, a:name, "") 233 return path == "" ? vam#DefaultPluginDirFromName(a:name) : path 234 endfun 235 let g:vim_addon_manager.plugin_dir_by_name = 'NixPluginLocation' 236 " tell Vim about VAM: 237 let &rtp.=(empty(&rtp)?"":','). g:nix_plugin_locations['vim-addon-manager'] 238 else 239 " standalone config 240 241 let &rtp.=(empty(&rtp)?"":',').c.plugin_root_dir.'/vim-addon-manager' 242 if !isdirectory(c.plugin_root_dir.'/vim-addon-manager/autoload') 243 " checkout VAM 244 execute '!git clone --depth=1 git://github.com/MarcWeber/vim-addon-manager ' 245 \ shellescape(c.plugin_root_dir.'/vim-addon-manager', 1) 246 endif 247 endif 248 249 " tell vam about which plugins to load when: 250 let l = [] 251 ${lib.concatMapStrings (p: "call add(l, ${toNix p})\n") vam.pluginDictionaries} 252 call vam#Scripts(l, {}) 253 ''); 254 255 # somebody else could provide these implementations 256 vundleImpl = ""; 257 258 neobundleImpl = ""; 259 260 261 in writeText "vimrc" '' 262 " minimal setup, generated by NIX 263 set nocompatible 264 filetype indent plugin on | syn on 265 266 ${vamImpl} 267 ${pathogenImpl} 268 ${vundleImpl} 269 ${neobundleImpl} 270 271 ${customRC} 272 ''; 273 274in 275 276rec { 277 inherit vimrcFile; 278 279 # shell script with custom name passing [-u vimrc] [-U gvimrc] to vim 280 vimWithRC = {vimExecutable, name ? null, vimrcFile ? null, gvimrcFile ? null}: 281 let rcOption = o: file: stdenv.lib.optionalString (file != null) "-${o} ${file}"; 282 in writeScriptBin (if name == null then "vim" else name) '' 283 #!/bin/sh 284 exec ${vimExecutable} ${rcOption "u" vimrcFile} ${rcOption "U" gvimrcFile} "$@" 285 ''; 286 287 # add a customize option to a vim derivation 288 makeCustomizable = vim: vim // { 289 customize = {name, vimrcConfig}: vimWithRC { 290 vimExecutable = "${vim}/bin/vim"; 291 inherit name; 292 vimrcFile = vimrcFile vimrcConfig; 293 }; 294 }; 295 296 pluginnames2Nix = {name, namefiles} : vim_configurable.customize { 297 inherit name; 298 vimrcConfig.vam.knownPlugins = vimPlugins; 299 vimrcConfig.vam.pluginDictionaries = ["vim-addon-vim2nix"]; # Using fork until patch is accepted by upstream 300 vimrcConfig.customRC = '' 301 " Yes - this is impure and will create the cache file and checkout vim-pi 302 " into ~/.vim/vim-addons 303 let g:vim_addon_manager.plugin_root_dir = "/tmp/vim2nix-".$USER 304 if !isdirectory(g:vim_addon_manager.plugin_root_dir) 305 call mkdir(g:vim_addon_manager.plugin_root_dir) 306 else 307 echom repeat("=", 80) 308 echom "WARNING: reusing cache directory :".g:vim_addon_manager.plugin_root_dir 309 echom repeat("=", 80) 310 endif 311 let opts = {} 312 let opts.nix_prefetch_git = "${../../../pkgs/build-support/fetchgit/nix-prefetch-git}" 313 let opts.nix_prefetch_hg = "${../../../pkgs/build-support/fetchhg/nix-prefetch-hg}" 314 let opts.cache_file = g:vim_addon_manager.plugin_root_dir.'/cache' 315 let opts.plugin_dictionaries = [] 316 ${lib.concatMapStrings (file: "let opts.plugin_dictionaries += map(readfile(\"${file}\"), 'eval(v:val)')\n") namefiles } 317 318 " uncomment for debugging failures 319 " let opts.try_catch = 0 320 321 " add more files 322 " let opts.plugin_dictionaries += map(.. other file ) 323 call nix#ExportPluginsForNix(opts) 324 ''; 325 }; 326 327 rtpPath = "share/vim-plugins"; 328 329 vimHelpTags = '' 330 vimHelpTags(){ 331 if [ -d "$1/doc" ]; then 332 ${vim}/bin/vim -N -u NONE -i NONE -n -e -s -c "helptags $1/doc" +quit! 333 fi 334 } 335 ''; 336 337 addRtp = path: derivation: 338 derivation // { rtp = "${derivation}/${path}"; }; 339 340 buildVimPlugin = a@{ 341 name, 342 namePrefix ? "vimplugin-", 343 src, 344 unpackPhase ? "", 345 configurePhase ? "", 346 buildPhase ? "", 347 path ? (builtins.parseDrvName name).name, 348 addonInfo ? null, 349 ... 350 }: 351 addRtp "${rtpPath}/${path}" (stdenv.mkDerivation (a // { 352 name = namePrefix + name; 353 354 inherit unpackPhase configurePhase buildPhase addonInfo; 355 356 installPhase = '' 357 target=$out/${rtpPath}/${path} 358 mkdir -p $out/${rtpPath} 359 cp -r . $target 360 ${vimHelpTags} 361 vimHelpTags $target 362 if [ -n "$addonInfo" ]; then 363 echo "$addonInfo" > $target/addon-info.json 364 fi 365 ''; 366 })); 367 368 buildVimPluginFrom2Nix = a: buildVimPlugin ({ 369 buildPhase = ":"; 370 configurePhase =":"; 371 } // a); 372 373 # test cases: 374 test_vim_with_vim_addon_nix_using_vam = vim_configurable.customize { 375 name = "vim-with-vim-addon-nix-using-vam"; 376 vimrcConfig.vam.pluginDictionaries = [{name = "vim-addon-nix"; }]; 377 }; 378 379 test_vim_with_vim_addon_nix_using_pathogen = vim_configurable.customize { 380 name = "vim-with-vim-addon-nix-using-pathogen"; 381 vimrcConfig.pathogen.pluginNames = [ "vim-addon-nix" ]; 382 }; 383 384}