├── .gitignore ├── README.md ├── addon-info.json ├── autoload ├── builtins.dump └── vim_addon_nix.vim ├── doc └── addon-nix.txt ├── ftplugin └── nix.vim ├── other.txt ├── plugin └── vim-addon-nix.vim ├── snippets ├── nix.nix └── nix.snippets └── syntax └── nix.vim /.gitignore: -------------------------------------------------------------------------------- 1 | doc/tags 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | vim-addon-nix 2 | ============= 3 | See doc/addon-nix.txt 4 | 5 | provides 6 | * goto thing at cursor implementation (to follow import .. paths) 7 | * vim-addon-action nix evaluation 8 | * uses nix-instantiate to syntax check a .nix file on buf write 9 | 10 | related work 11 | ============ 12 | there is nix-repl, too (see nixpkgs) 13 | -------------------------------------------------------------------------------- /addon-info.json: -------------------------------------------------------------------------------- 1 | { 2 | "name" : "vim-addon-nix", 3 | "version" : "0.1", 4 | "author" : "Marc Weber ", 5 | "maintainer" : "Marc Weber ", 6 | "repository" : {"type": "git", "url": "git://github.com/MarcWeber/vim-addon-nix.git"}, 7 | "dependencies" : { 8 | "vim-addon-mw-utils": {}, 9 | "tlib": {}, 10 | "vim-addon-actions": {}, 11 | "vim-addon-completion": {}, 12 | "vim-addon-goto-thing-at-cursor": {}, 13 | "vim-addon-errorformats": {} 14 | }, 15 | "description" : "some code assisting writing nix files" 16 | } 17 | -------------------------------------------------------------------------------- /autoload/builtins.dump: -------------------------------------------------------------------------------- 1 | {'currentTime': {'word': 'currentTime', 'menu': 'no documentation found for currentTime'}, 'getEnv': {'word': 'getEnv', 'menu': 'builtins s', 'info': 'getEnv returns the value of the environment variable s, or an empty string if the variable doesn’t exist. This function should be used with care, as it can introduce all sorts of nasty environment dependencies in your Nix expression.', 'dup': 1}, 'sub': {'word': 'sub', 'menu': 'builtins e1 e2', 'info': 'Return the difference between the integers e1 and e2.', 'dup': 1}, 'addErrorContext': {'word': 'addErrorContext', 'menu': 'no documentation found for addErrorContext'}, 'genericClosure': {'word': 'genericClosure', 'menu': 'no documentation found for genericClosure'}, 'add': {'word': 'add', 'menu': 'builtins e1 e2', 'info': 'Return the sum of the integers e1 and e2.', 'dup': 1}, 'unsafeDiscardOutputDependency': {'word': 'unsafeDiscardOutputDependency', 'menu': 'no documentation found for unsafeDiscardOutputDependency'}, 'functionArgs': {'word': 'functionArgs', 'menu': 'no documentation found for functionArgs'}, 'map': {'word': 'map', 'menu': 'builtins (concat "foo") ["bar" "bla" "abc"]', 'info': '', 'dup': 1}, 'isInt': {'word': 'isInt', 'menu': 'builtins e', 'info': 'Return true if e evaluates to a int, and false otherwise.', 'dup': 1}, 'builtins': {'word': 'builtins', 'menu': 'no documentation found for builtins'}, 'readFile': {'word': 'readFile', 'menu': 'builtins path', 'info': 'Return the contents of the file path as a string.', 'dup': 1}, 'attrNames': {'word': 'attrNames', 'menu': 'builtins attrs', 'info': 'Return the names of the attributes in the attribute set attrs in a sorted list. For instance, builtins.attrNames {y = 1; x = "foo";} evaluates to ["x" "y"]. There is no built-in function attrValues, but you can easily define it yourself:', 'dup': 1}, 'unsafeDiscardStringContext': {'word': 'unsafeDiscardStringContext', 'menu': 'no documentation found for unsafeDiscardStringContext'}, 'stringLength': {'word': 'stringLength', 'menu': 'builtins e', 'info': 'Return the length of the string e. If e is not a string, evaluation is aborted.', 'dup': 1}, 'tail': {'word': 'tail', 'menu': 'builtins list', 'info': 'Return the second to last elements of a list; abort evaluation if the argument isn’t a list or is an empty list.', 'dup': 1}, 'getAttr': {'word': 'getAttr', 'menu': 'builtins s attrs', 'info': 'getAttr returns the attribute named s from the attribute set attrs. Evaluation aborts if the attribute doesn’t exist. This is a dynamic version of the . operator, since s is an expression rather than an identifier.', 'dup': 1}, 'toString': {'word': 'toString', 'menu': 'builtins e', 'info': 'Convert the expression e to a string. e can be a string (in which case toString is a no-op) or a path (e.g., toString /foo/bar yields "/foo/bar".', 'dup': 1}, 'hasAttr': {'word': 'hasAttr', 'menu': 'builtins s attrs', 'info': 'hasAttr returns true if the attribute set attrs has an attribute named s, and false otherwise. This is a dynamic version of the ? operator, since s is an expression rather than an identifier.', 'dup': 1}, 'baseNameOf': {'word': 'baseNameOf', 'menu': 'builtins s', 'info': 'Return the base name of the string s, that is, everything following the final slash in the string. This is similar to the GNU basename command.', 'dup': 1}, 'isList': {'word': 'isList', 'menu': 'builtins e', 'info': 'Return true if e evaluates to a list, and false otherwise.', 'dup': 1}, 'derivation': {'word': 'derivation', 'menu': 'builtins that adds a default value for system and always uses Bash as', 'info': '', 'dup': 1}, 'true': {'word': 'true', 'menu': 'builtins but the db4 argument set to null, then the evaluation fails.', 'info': '', 'dup': 1}, 'head': {'word': 'head', 'menu': 'builtins list', 'info': 'Return the first element of a list; abort evaluation if the argument isn’t a list or is an empty list. You can test whether a list is empty by comparing it with [].', 'dup': 1}, 'currentSystem': {'word': 'currentSystem', 'menu': 'no documentation found for currentSystem'}, 'lessThan': {'word': 'lessThan', 'menu': 'builtins e1 e2', 'info': 'Return true if the integer e1 is less than the integer e2, and false otherwise. Evaluation aborts if either e1 or e2 does not evaluate to an integer.', 'dup': 1}, 'tryEval': {'word': 'tryEval', 'menu': 'no documentation found for tryEval'}, 'substring': {'word': 'substring', 'menu': 'builtins start len s', 'info': 'Return the substring of s from character position start (zero-based) up to but not including start + len. If start is greater than the length of the string, an empty string is returned, and if start + len lies beyond the end of the string, only the substring up to the end of the string is returned. start must be non-negative.', 'dup': 1}, 'import': {'word': 'import', 'menu': 'builtins path', 'info': 'Load, parse and return the Nix expression in the file path. Evaluation aborts if the file doesn’t exist or contains an incorrect Nix expression. import implements Nix’s module system: you can put any Nix expression (such as an attribute set or a function) in a separate file, and use it from Nix expressions in other files.', 'dup': 1}, 'isAttrs': {'word': 'isAttrs', 'menu': 'builtins e', 'info': 'Return true if e evaluates to an attribute set, and false otherwise.', 'dup': 1}, 'compareVersions': {'word': 'compareVersions', 'menu': 'builtins s1 s2', 'info': 'Compare two strings representing versions and return -1 if version s1 is older than version s2, 0 if they are the same, and 1 if s1 is newer than s2. The version comparison algorithm is the same as the one used by [274]nix-env -u.', 'dup': 1}, 'isFunction': {'word': 'isFunction', 'menu': 'builtins e', 'info': 'Return true if e evaluates to a function, and false otherwise.', 'dup': 1}, 'storePath': {'word': 'storePath', 'menu': 'no documentation found for storePath'}, 'derivationStrict': {'word': 'derivationStrict', 'menu': 'no documentation found for derivationStrict'}, 'toXML': {'word': 'toXML', 'menu': 'builtins e', 'info': 'Return a string containing an XML representation of e. The main application for toXML is to communicate information with the builder in a more structured format than plain environment variables.', 'dup': 1}, 'isString': {'word': 'isString', 'menu': 'builtins e', 'info': 'Return true if e evaluates to a string, and false otherwise.', 'dup': 1}, 'div': {'word': 'div', 'menu': 'builtins e1 e2', 'info': 'Return the quotient of the integers e1 and e2.', 'dup': 1}, 'isBool': {'word': 'isBool', 'menu': 'builtins e', 'info': 'Return true if e evaluates to a bool, and false otherwise.', 'dup': 1}, 'null': {'word': 'null', 'menu': 'no documentation found for null'}, 'filterSource': {'word': 'filterSource', 'menu': 'builtins e1 e2', 'info': 'This function allows you to copy sources into the Nix store while filtering certain files. For instance, suppose that you want to use the directory source-dir as an input to a Nix expression, e.g.', 'dup': 1}, 'pathExists': {'word': 'pathExists', 'menu': 'builtins path', 'info': 'Return true if the path path exists, and false otherwise. One application of this function is to conditionally include a Nix expression containing user configuration:', 'dup': 1}, 'dirOf': {'word': 'dirOf', 'menu': 'builtins s', 'info': 'Return the directory part of the string s, that is, everything before the final slash in the string. This is similar to the GNU dirname command.', 'dup': 1}, 'parseDrvName': {'word': 'parseDrvName', 'menu': 'builtins s', 'info': 'Split the string s into a package name and version. The package name is everything up to but not including the first dash followed by a digit, and the version is everything following that dash. The result is returned in an attribute set {name, version}. Thus, builtins.parseDrvName "nix-0.12pre12876" returns {name = "nix"; version = "0.12pre12876";}.', 'dup': 1}, 'trace': {'word': 'trace', 'menu': 'builtins e1 e2', 'info': 'Evaluate e1 and print its abstract syntax representation on standard error. Then return e2. This function is useful for debugging.', 'dup': 1}, 'removeAttrs': {'word': 'removeAttrs', 'menu': 'builtins attrs list', 'info': 'Remove the attributes listed in list from the attribute set attrs. The attributes don’t have to exist in attrs. For instance,', 'dup': 1}, 'toPath': {'word': 'toPath', 'menu': 'builtins s', 'info': 'Convert the string value s into a path value. The string s must represent an absolute path (i.e., must start with /). The path need not exist. The resulting path is canonicalised, e.g., builtins.toPath "//foo/xyzzy/../bar/" returns /foo/bar.', 'dup': 1}, 'false': {'word': 'false', 'menu': 'builtins otherwise. Evaluation aborts if either e1 or e2 does not', 'info': '', 'dup': 1}, 'throw': {'word': 'throw', 'menu': 'builtins s', 'info': 'Throw an error message s. This usually aborts Nix expression evaluation, but in nix-env -qa and other commands that try to evaluate a set of derivations to get information about those derivations, a derivation that throws an error is silently skipped (which is not the case for abort).', 'dup': 1}, 'length': {'word': 'length', 'menu': 'builtins e', 'info': 'Return the length of the list e.', 'dup': 1}, 'isNull': {'word': 'isNull', 'menu': 'builtins e', 'info': 'Return true if e evaluates to null, and false otherwise.', 'dup': 1}, 'intersectAttrs': {'word': 'intersectAttrs', 'menu': 'builtins e1 e2', 'info': 'Return an attribute set consisting of the attributes in the set e2 that also exist in the set e1.', 'dup': 1}, 'abort': {'word': 'abort', 'menu': 'builtins s', 'info': 'Abort Nix expression evaluation, print error message s.', 'dup': 1}, 'toFile': {'word': 'toFile', 'menu': 'builtins name s', 'info': 'Store the string s in a file in the Nix store and return its path. The file has suffix name. This file can be used as an input to derivations. One application is to write builders “inline”. For instance, the following Nix expression combines [276]Example 5.1, “Nix expression for GNU Hello (default.nix)” and [277]Example 5.2, “Build script for GNU Hello (builder.sh)” into one file:', 'dup': 1}, 'listToAttrs': {'word': 'listToAttrs', 'menu': 'builtins e', 'info': 'Construct an attribute set from a list specifying the names and values of each attribute. Each element of the list should be an attribute set consisting of a string-valued attribute name specifying the name of the attribute, and an attribute value specifying its value. Example:', 'dup': 1}, 'mul': {'word': 'mul', 'menu': 'builtins e1 e2', 'info': 'Return the product of the integers e1 and e2.', 'dup': 1}} 2 | -------------------------------------------------------------------------------- /autoload/vim_addon_nix.vim: -------------------------------------------------------------------------------- 1 | " exec vam#DefineAndBind('s:c','vim_addon_nix','{}') 2 | if !exists('vim_addon_nix') | let vim_addon_nix = {} | endif | let s:c = g:vim_addon_nix 3 | 4 | if !exists('g:nix_syntax_check_error_list') 5 | " use location list by default 6 | let g:nix_syntax_check_error_list = 'l' 7 | endif 8 | 9 | fun! vim_addon_nix#CheckSyntax() 10 | let p = g:nix_syntax_check_error_list 11 | if !exists('s:tmpfile') 12 | let s:tmpfile = tempname() 13 | endif 14 | call system('nix-instantiate --parse-only '.shellescape(expand('%')).' &> '.s:tmpfile) 15 | let succ = v:shell_error == 0 16 | let old_was_error = exists('b:nix_was_error') && b:nix_was_error 17 | let b:nix_was_error = !succ 18 | " if there was an error or if privous run had an error 19 | " load result into quickfix or error list 20 | if !succ || old_was_error 21 | Errorformat nix 22 | exec p.'file '.s:tmpfile 23 | exec succ ? p.'close' : p.'open' 24 | endif 25 | endf 26 | 27 | " provide mapping running nix-instantiate (see vim-addon-actions, plugin/vim-addon-nix.vim) 28 | fun! vim_addon_nix#CompileRHS(command_args) 29 | let target = a:0 > 0 ? a:1 : "" 30 | let ef = vim_addon_errorformats#QuoteForAssignment(vim_addon_errorformats#ErrorFormatLines('nix')) 31 | let args = actions#VerifyArgs(a:command_args+[expand('%')]) 32 | return "call bg#RunQF(".string(args).", 'c', ".string(ef).")" 33 | endfun 34 | 35 | " (vim-addon-goto-thing-at-cursor, see plugin/vim-addon-nix.vim) 36 | fun! vim_addon_nix#gfHandler() 37 | let res = [ expand(expand('%:h').'/'.matchstr(expand(''),'[^;()[\]]*')) ] 38 | for match in [matchstr(getline('.'), 'import\s*\zs[^;) \t]\+\ze'), matchstr(getline('.'), 'call\S*\s*\zs[^;) \t]\+\ze')] 39 | if match == "" | continue | endif 40 | call add(res, expand('%:h').'/'.match) 41 | endfor 42 | 43 | " if import string is a directory append '/default.nix' : 44 | " everything not having an extension is treated as directory 45 | 46 | call map(res, 'v:val =~ '.string('\.[^./]\+$').' ? v:val : v:val.'.string('/default.nix')) 47 | 48 | let list = matchlist(getline('.'), '.*selectVersion\s\+\(\S*\)\s\+"\([^"]\+\)"') 49 | if (!empty(list)) 50 | " something like this has been matched selectVersion ../applications/version-management/codeville "0.8.0" 51 | call add(res, expand('%:h').'/'.list[1].'/'.list[2].'.nix') 52 | else 53 | " something with var instead of "0.8.x" has been matched 54 | let list = matchlist(getline('.'), '.*selectVersion\s\+\(\S*\)\s\+\(\S\+\)') 55 | if (!empty(list)) 56 | call extend(res, split(glob(expand('%:h').'/'.list[1].'/*.nix'), "\n")) 57 | " also add subdirectory files (there won't be that many) 58 | call extend(res, filter(split(glob(expand('%:h').'/'.list[1].'/*/*.nix'), "\n"),'1')) 59 | endif 60 | endif 61 | return res 62 | endf 63 | 64 | fun! vim_addon_nix#DirsToTag() 65 | " probably it makes sense sense to tag ../* of dir 66 | let dir = fnamemodify($NIXPKGS_ALL,':h:h:h') 67 | if isdirectory(dir) 68 | return [dir] 69 | endf 70 | 71 | fun! vim_addon_nix#NixRetagAllPackages() 72 | for d in vim_addon_nix#DirsToTag() 73 | call vcs_checkouts#ExecIndir([{'d': d, 'c': s:c.tag_command.' .'}]) 74 | endfor 75 | endf 76 | 77 | " does a word match (for completion) 78 | fun! vim_addon_nix#Match(m) 79 | let p = get(s:c.patterns, 'vim_regex','') 80 | return a:m =~ '^'.s:c.base || (p != "" && a:m =~ p) 81 | endf 82 | 83 | fun! vim_addon_nix#FuzzyNixCompletion(findstart, base) 84 | if a:findstart 85 | let [bc,ac] = vim_addon_completion#BcAc() 86 | let s:match_text = matchstr(bc, '\zs[^{.()[\]{}\t ]*$') 87 | let s:context = matchstr(bc, '\zs[^{.() \t[\]]\+\ze\.[^.()[\]{}\t ]*$') 88 | if s:context !~ 'lib\|builtins\|types\|maintainers\|licenses' 89 | let s:context = '' 90 | endif 91 | let s:start = len(bc)-len(s:match_text) 92 | return s:start 93 | else 94 | let base = a:base 95 | let s:c.context = s:context 96 | if s:c.context != '' 97 | " if you complete b: l: or t: you'll get those scopes only 98 | let contexts = {'b:': 'builtins', 'l:': 'lib', 't:': 'types','m:' : 'maintainers'} 99 | for [c, context] in items(contexts) 100 | if base =~ '^'.c 101 | " overwrite context 102 | let s:c.context = context 103 | let base = base[len(c):] 104 | break 105 | endif 106 | unlet c context 107 | endfor 108 | endif 109 | 110 | let s:c.base = base 111 | 112 | let patterns = vim_addon_completion#AdditionalCompletionMatchPatterns(base 113 | \ , "ocaml_completion", { 'match_beginning_of_string': 1}) 114 | let s:c.patterns = patterns 115 | 116 | for f in values(s:c.completion_sources) 117 | call funcref#Call(f) 118 | endfor 119 | return [] 120 | endf 121 | 122 | let s:builtins_dump = expand(':h').'/builtins.dump' 123 | 124 | fun! vim_addon_nix#GetBuiltins() 125 | 126 | let tmp = tempname() 127 | call writefile(["builtins.attrNames builtins"], tmp) 128 | " list of builtin names: 129 | let g:result = substitute(join(split(system("nix-instantiate --eval-only --strict ".tmp),"\n"),""),'" "','","','g') 130 | let g:names = eval(g:result) 131 | " let g:manual = system("elinks --dump 'http://hydra.nixos.org/build/757694/download/1/manual/'") 132 | let lines = split(g:manual, "\n") 133 | 134 | let first_line = 1 135 | while lines[first_line] !~ 'Built-in functions' 136 | let first_line += 1 137 | endwhile 138 | 139 | let g:builtins = {} 140 | for n in g:names 141 | let regex = '^\s*\%(builtins\.\)\?'.n.'\s\+\zs.*' 142 | let start = first_line 143 | while start < len(lines) && lines[start] !~ regex 144 | let start +=1 145 | endwhile 146 | if start == len(lines) 147 | let menu = "no documentation found for ".n 148 | let g:builtins[n] = {'word': n, 'menu': menu} 149 | else 150 | let args = matchstr( lines[start], regex ) 151 | let menu = printf('%-30s %s', "builtins", args) 152 | 153 | let info = [] 154 | while lines[start+2] =~ ' ' 155 | call add(info, matchstr(lines[start+2], '\s*\zs.*')) 156 | let start += 1 157 | endwhile 158 | 159 | let g:builtins[n] = {'word': n, 'menu': menu, 'info' : join(info," "), 'dup': 1} 160 | endif 161 | endfor 162 | call writefile([string(g:builtins)], s:builtins_dump) 163 | endf 164 | 165 | fun! vim_addon_nix#BuiltinsCompletion() 166 | if s:c.context != '' && s:c.context != "builtins" | return | endif 167 | 168 | " check completness by evaluating: 169 | for [f,dict] in items(eval(readfile(s:builtins_dump)[0])) 170 | if !vim_addon_nix#Match(f) | continue | endif 171 | call complete_add(dict) 172 | unlet f dict 173 | endfor 174 | endf 175 | 176 | fun! vim_addon_nix#TagBasedCompletion() 177 | 178 | if s:c.context == "builtins" | return | endif 179 | 180 | let break_on_context_missmatch = '0' 181 | if s:c.context == "lib" 182 | let break_on_context_missmatch = "m.filename !~ '[/\\\\]lib[/\\\\]'" 183 | elseif s:c.context == "licenses" 184 | let break_on_context_missmatch = "m.filename !~ '[/\\\\]licenses.nix'" 185 | elseif s:c.context == "types" 186 | let break_on_context_missmatch = "m.filename !~ '[/\\\\]types.nix'" 187 | elseif s:c.context == "maintainers" 188 | let break_on_context_missmatch = "m.filename !~ '[/\\\\]maintainers.nix'" 189 | endif 190 | 191 | let break_on_context_missmatch = 'let do_break = '.break_on_context_missmatch 192 | 193 | for m in taglist('^'. s:c.base[:0]) 194 | if complete_check()| return | endif 195 | " ignore default.nix files. They usually only contain name, buildInputs etc 196 | if m.filename =~ 'default.nix$' || !vim_addon_nix#Match(m.name) | continue | endif 197 | 198 | exec break_on_context_missmatch 199 | " can't use continue in exec 200 | if do_break | continue | endif 201 | 202 | let fn = fnamemodify(m.filename, ':h:t').'/'.fnamemodify(m.filename, ':t') 203 | let args_and_rest = matchstr(m.cmd, '^\/.\{-}\zs=.*\ze\$\/') 204 | let menu = printf('%-30s %s', fn, args_and_rest) 205 | call complete_add({'word': m.name, 'menu': menu, 'info' : menu."\n".m.filename, 'dup': 1}) 206 | endfor 207 | endf 208 | 209 | 210 | " option completion based on man page which you can generate automatically. 211 | fun! vim_addon_nix#OptionsCached() abort 212 | if !has_key(s:c, 'options') 213 | " I agree this is very fuzzy, quick and dirty, but works 214 | let options = {} 215 | Man configuration.nix 216 | 217 | let key = '' 218 | let gathered = [] 219 | for l in getline(0, '$') 220 | if l =~ '^ \S' 221 | " new section 222 | if key != '' 223 | let options[key] = {'description': gathered} 224 | endif 225 | let key = l[7:] 226 | let gathered = [] 227 | else 228 | call add(gathered, l) 229 | endif 230 | endfor 231 | 232 | if key != '' 233 | let options[key] = {'description': gathered} 234 | endif 235 | 236 | " quit man page 237 | bw! 238 | let s:c.options = options 239 | endif 240 | return s:c.options 241 | endf 242 | 243 | fun! vim_addon_nix#OptionCompletion(findstart, base) 244 | if a:findstart 245 | let [bc,ac] = vim_addon_completion#BcAc() 246 | let s:match_text = matchstr(bc, '\zs[^{()[\]{}\t ]*$') 247 | let s:start = len(bc)-len(s:match_text) 248 | return s:start 249 | else 250 | let base = a:base 251 | let result = [] 252 | 253 | for [key,v] in items(vim_addon_nix#OptionsCached()) 254 | if key =~? a:base 255 | let defined_at = get(filter(copy(v.description),'v:val =~ '.string('^ <') ),0,'') 256 | let description = join(v.description,"\n") 257 | if description =~ 'Obsolete name' 258 | let defined_at .= ' obsolete' 259 | endif 260 | call add(result, {'word': key, 'menu': defined_at, 'info': description}) 261 | endif 262 | endfor 263 | return result 264 | endf 265 | -------------------------------------------------------------------------------- /doc/addon-nix.txt: -------------------------------------------------------------------------------- 1 | INSTALLATION: 2 | ============= 3 | I recommend using my vim-addon-manager. 4 | You can also put the top directory of this pluign and its dependencies into a 5 | &runtime path (see vim-nix-addon-info.txt) 6 | 7 | FEATURES: 8 | ========= 9 | 10 | - quick mappings to nix-instantiate .nix files. You can teach the .nix language 11 | yourself or run tests easily. 12 | - \gf mapping to jump to import files (automatically finding the default.nix) 13 | or proposing to create those files (see vim-addon-goto-thing-at-cursor) 14 | - some snippets which can be used with snipMate plugin 15 | - folding for all-packages.nix (by ### lines) 16 | - settings stuff such as indentation characters tec 17 | - configuration.nix option completion based on man configuration.nix output [C2] 18 | - builtins. lib. maintainers. licenses. types. completion (based on tag files). [C1] 19 | 20 | SETUP: 21 | ====== 22 | 23 | put into your .vimrc: 24 | 25 | " this will define the correct maintainers line in meta tags: 26 | let g:nix_maintainer="YOURNAME" 27 | 28 | 29 | TIP: 30 | ==== 31 | Use a mapping like this to open all-packages.nix. 32 | It picks all-packages.nix of the current nixpkgs top level directory. 33 | If that doesn't exist NIXPKGS_ALL is used to find all-packages.nix 34 | noremap \aps : if filereadable('pkgs/top-level/all-packages.nix') e pkgs/top-level/all-packages.nix else exec 'e '.expand("$NIXPKGS_ALL") endif 35 | 36 | [C1] completion howto: 37 | ===================== 38 | a) Install ctagsWrapped.ctagsWrapped (from all-packages.nix) It contains fuzzy 39 | regexs to find attr names. 40 | b) define NIXPKGS_ALL 41 | c) open Vim, run NixRetagAllPackages 42 | (make sure that the tag files contain /.../ patterns instead of file names 43 | because they will be used for completion for performance reasons 44 | 45 | filtering completion results: 46 | 47 | using l:get you'll only get matches from lib/*.nix 48 | using b:... you'll only get matches form builtins 49 | using m:... you'll only get matches form maintainers 50 | using t:... you'll only get matches form types 51 | 52 | lib. 53 | builtins. 54 | types. 55 | maintainers. 56 | will be recognized automatically. 57 | 58 | 59 | configuration.nix option completion: c-x c-c 60 | 61 | [C2] completion howto: 62 | ===================== 63 | set nixos configuration option 64 | nixosManual.enable = true; # however takes little time to build 65 | 66 | TODO: 67 | ===== 68 | fix syntax and move the file into this repository (-> vim_configurable expression) 69 | 70 | historical note: some code was taken from my tovl into this repository 71 | 72 | BUGS: 73 | ===== 74 | lib. will take too longe because taglist('^') takes forever 75 | -------------------------------------------------------------------------------- /ftplugin/nix.vim: -------------------------------------------------------------------------------- 1 | if !exists('vim_addon_nix') | let vim_addon_nix = {} | endif | let s:c = g:vim_addon_nix 2 | 3 | if s:c.nix_folding 4 | " don't fold if there are no heaaders (default.nix files) 5 | if search('###','nw') > 0 6 | setlocal foldexpr=getline(v:lnum)=~'###'?'>1':1 7 | setlocal foldmethod=expr 8 | setlocal foldtext=getline(v:foldstart) 9 | endif 10 | endif 11 | 12 | setlocal sw=2 13 | 14 | call on_thing_handler#AddOnThingHandler('b', funcref#Function('vim_addon_nix#gfHandler')) 15 | 16 | " this search can be used so often and is so useful .. 17 | noremap /^ 18 | 19 | " will rewrite this all using editor-cells 20 | " call vim_addon_completion#InoremapCompletions(s:c, [ 21 | " \ { 'setting_keys' : ['complete_lhs'], 'fun': 'vim_addon_nix#FuzzyNixCompletion'}, 22 | " \ { 'setting_keys' : ['complete_lhs_option'], 'fun': 'vim_addon_nix#OptionCompletion'}, 23 | " \ ] ) 24 | -------------------------------------------------------------------------------- /other.txt: -------------------------------------------------------------------------------- 1 | " script I wrote once to fix import paths in all-packages.nix 2 | " Fix imports 3 | 4 | "let g:cache=split(glob('**'),"\n") 5 | 6 | "let g:vim_fix_nix_dict = {} 7 | 8 | "[> build up dict containing list (we allow multiple directroies ending the same 9 | "[> way) 10 | "for i in g:cache 11 | " let lastPathComponent = fnamemodify(i, ":t") 12 | " let g:vim_fix_nix_dict[lastPathComponent] = get(g:vim_fix_nix_dict, lastPathComponent, []) 13 | " call add(g:vim_fix_nix_dict[lastPathComponent], i) 14 | "endfor 15 | 16 | "fun! FixNext() 17 | " set cul 18 | " [> assuming paths don't contain spaces.. 19 | " call search('import\s\+"\?','e') 20 | " normal lvE 21 | 22 | " [> check wether last char is either " or ) 23 | " [> this won't work for unicode chars.. I don't mind here 24 | " let char = getline(line('.'))[col('.')-1] 25 | " if char == ')' || char == '"' 26 | " normal h 27 | " endif 28 | " [> copy selection 29 | " normal y 30 | " let path = @[> 31 | 32 | " let abs_path = getcwd().'/'.expand('%:h').'/'.path 33 | " if (!isdirectory(abs_path) && !filereadable(abs_path)) 34 | " let last = fnamemodify(abs_path, ":t") 35 | " let found = get(g:vim_fix_nix_dict, last, []) 36 | " if empty(found) 37 | " echo "no matches found" 38 | " else 39 | " let x = tovl#ui#choice#LetUserSelectIfThereIsAChoice('select match for '.path, found) 40 | " let relative = substitute(tlib#file#Relative(x, expand('%:h')),'/$','','') 41 | " [> prepend ./ 42 | " let relative = substitute(relative,'^\([^.]\)','./\1','') 43 | " normal jjjzbkkk 44 | " redraw 45 | " echo 'replace '.path.' by '.relative.' ? [y]' 46 | " if nr2char(getchar()) == 'y' 47 | " exec 'silent! normal gvs'.relative 48 | " endif 49 | " endif 50 | " else 51 | " [> does exist, search next 52 | " call FixNext() 53 | " endif 54 | "endf 55 | 56 | "command! FixNext call FixNext() 57 | "noremap :FixNext 58 | " 59 | " 60 | "fun! Test() 61 | " let d = {} 62 | " for i in getline(1,line('$')) 63 | " let m = matchlist(i, '^ \s*\(\S*\)\s*=\s*import\s*../\(\S*\).*') 64 | " if empty(m) 65 | " continue 66 | " endif 67 | " let m2 = matchstr(m[2], '\zs.*/\ze.*$') 68 | " if empty(m) 69 | " echo m 70 | " echo i 71 | " else 72 | " let l = get(d, m2, []) 73 | " call add(l, m[1]) 74 | " let d[m2] = l 75 | " endif 76 | " endfor 77 | " let final = [] 78 | " for [k,l] in items(d) 79 | " call add(final, k) 80 | " for lin in l 81 | " call add(final, ' '.lin) 82 | " endfor 83 | " endfor 84 | " put=final 85 | "endf 86 | "call Test() 87 | -------------------------------------------------------------------------------- /plugin/vim-addon-nix.vim: -------------------------------------------------------------------------------- 1 | " exec vam#DefineAndBind('s:c','vim_addon_nix','{}') 2 | if !exists('vim_addon_nix') | let vim_addon_nix = {} | endif | let s:c = g:vim_addon_nix 3 | let s:c.complete_lhs = get(s:c, 'complete_lhs', '') 4 | let s:c.complete_lhs_option = get(s:c, 'complete_lhs_option', '') 5 | let s:c.nix_folding = get(s:c, 'nix_folding', 0) 6 | 7 | let s:c.completion_sources = get(s:c,'completion_sources',{}) 8 | let s:c.completion_sources.tag_based_completion = funcref#Function('vim_addon_nix#TagBasedCompletion') 9 | let s:c.completion_sources.builtin_completion = funcref#Function('vim_addon_nix#BuiltinsCompletion') 10 | let s:c.tag_command = get(s:c, 'tag_command', 'ctags-svn-wrapped -R') 11 | 12 | " register functions setting up nix-instantiate invokations for testing and 13 | " learning purposes. See nix-addon-actions 14 | for command_args in [["nix-instantiate","--eval-only","--strict"], ["nix-instantiate","--eval-only","--strict","--xml"]] 15 | call actions#AddAction('run '.join(command_args," "), {'action': funcref#Function('vim_addon_nix#CompileRHS', { 'args' : [command_args] })}) 16 | endfor 17 | 18 | command! NixRetagAllPackages call vim_addon_nix#NixRetagAllPackages() 19 | 20 | " set filetype to nix for *.nix files: 21 | augroup DefaultNix 22 | autocmd BufRead,BufNewFile *.nix setlocal ft=nix | exec 'setlocal tags+='.join(map(vim_addon_nix#DirsToTag(),'",".v:val."/tags"'),"") 23 | autocmd BufWritePost *.nix call vim_addon_nix#CheckSyntax() 24 | augroup end 25 | 26 | " smarter way to pen all-packages.nix: 27 | noremap \aps : if filereadable('pkgs/top-level/all-packages.nix') e pkgs/top-level/all-packages.nix else exec 'e '.expand("$NIXPKGS_ALL").'/pkgs/top-level/all-packages.nix' endif 28 | -------------------------------------------------------------------------------- /snippets/nix.nix: -------------------------------------------------------------------------------- 1 | snippet derivation 2 | <++> = stdenv.mkDerivation { 3 | name = "<++>"; 4 | buildInputs = []; 5 | src =