1 " This file is part of NIT ( http://www.nitlanguage.org ).
3 " Licensed under the Apache License, Version 2.0 (the "License");
4 " you may not use this file except in compliance with the License.
5 " You may obtain a copy of the License at
7 " http://www.apache.org/licenses/LICENSE-2.0
9 " Unless required by applicable law or agreed to in writing, software
10 " distributed under the License is distributed on an "AS IS" BASIS,
11 " WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 " See the License for the specific language governing permissions and
13 " limitations under the License.
15 " Nit plugin for Vim, provides some advanced features
21 if exists("loaded_nit_plugin")
24 let loaded_nit_plugin = 1
26 " Scan all relevant Nit modules for the current directory to autocomplete
28 " The guard `g:nit_complete_done` ensures that its body is executed only
29 " once. The call to `nitls -M` analyzses the current directory. However,
30 " updating the module list can be forced using ForceNitComplete.
32 " To activate, add the following line to ~/.vimrc
34 " autocmd Filetype nit call NitComplete()
35 function NitComplete()
36 if !exists("g:nit_complete_done")
37 let g:nit_complete_done = 1
39 " Reset or backup the original complete
40 if !exists("g:nit_complete_backup")
41 let g:nit_complete_backup = &complete
43 silent let &complete = g:nit_complete_backup
47 " This gives us better results for Nit
49 set completeopt=longest,menuone,preview
51 " Do not predict small 3 letters keywords (or their prefix), they slow down
52 " prediction and some also require double-enter on end of line.
53 let g:acp_behaviorKeywordIgnores = ['new', 'var', 'in', 'do', 'els', 'end', 'ret', 'for', 'fun']
55 " Use nitls to compute all interesting files from the current directory and the standard library
56 for file in split(system('nitls -M standard .', '\n'))
57 silent let &complete = &complete . ',s' . file
61 " Compatibility with AutoComplPop
62 let g:acp_completeOption = &complete
63 let g:acp_ignorecaseOption = &ignorecase
65 " Redraw in case the user pressed some keys while waiting
70 " Force updating the Nit modules used for autocomplete
72 " It is recommended to manually call this function as needed. It can be mapped
75 " map <F2> :call ForceNitComplete()
77 " For small projects (or fast computers) you might want to call it on each
79 function ForceNitComplete()
80 unlet! g:nit_complete_done
84 " Internal function to search for lines in `path` corresponding to the partial
85 " word `base`. Adds found and formated match to `matches`.
87 " Will order the results in 3 levels:
89 " 2. Common prefix matches
90 " 3. Substring matches
91 fun NitOmnifuncAddFromFile(base, matches, path)
92 let prefix_matches = []
93 let substring_matches = []
95 " Where are the generated metadata files?
96 if empty($NIT_VIM_DIR)
97 let metadata_dir = $HOME . '/.vim/nit'
99 let metadata_dir = $NIT_VIM_DIR
102 let path = metadata_dir . '/' . a:path
103 " Is there generated custom metadata files?
104 if ! filereadable(path)
105 let path = s:script_dir . '/' . a:path
107 " Is there standard metadata files?
108 if ! filereadable(path)
113 for line in readfile(path)
114 let words = split(line, '#====#', 1)
115 let name = get(words, 0, '')
120 call NitOmnifuncAddAMatch(a:matches, words, name)
121 elseif name =~ '^'.a:base
122 " Common-prefix match
123 call NitOmnifuncAddAMatch(prefix_matches, words, name)
124 elseif name =~ a:base
126 call NitOmnifuncAddAMatch(substring_matches, words, name)
130 " Assemble the final match list
131 call extend(a:matches, sort(prefix_matches))
132 call extend(a:matches, sort(substring_matches))
135 " Internal function to search parse the information from a metadata line
136 fun NitOmnifuncAddAMatch(matches, words, name)
137 let pretty = get(a:words, 1, '')
138 let synopsis = get(a:words, 2, '')
139 let desc = get(a:words, 3, '')
140 let desc = join(split(desc, '#nnnn#', 1), "\n")
141 if strlen(pretty) > 40
142 let pretty = pretty[:39] . '…'
144 call add(a:matches, {'word': a:name, 'abbr': pretty, 'menu': synopsis, 'info': desc, 'dup': 1})
147 " Omnifunc using metadata files generated by nitpick to offer better
148 " contextual autocomplete for Nit source code.
149 fun NitOmnifunc(findstart, base)
151 " locate the start of the word
152 let line = getline('.')
153 let start = col('.') - 1
154 while start > 0 && line[start - 1] =~ '\w'
159 " find keyword matching with "a:base"
162 " Advanced suggestions
163 let cursor_line = getline('.')
165 " Content of the line before the partial word
166 let line_prev_cursor = cursor_line[:col('.')-1]
168 let prev_char_at = strlen(line_prev_cursor) - 1
169 while prev_char_at > 0 && line_prev_cursor[prev_char_at] =~ '\s'
170 let prev_char_at -= 1
173 " Non whitespace char just before the partial word
174 let prev_char = line_prev_cursor[prev_char_at]
176 " Nity words on the current line before the partial word
177 let prev_words = split(line_prev_cursor, '\W\+')
179 " The word right before the partial word
180 let prev_word = get(prev_words, -1, '')
182 " Have we found a promising heuristic yet?
186 if prev_word == 'import' && ! (line_prev_cursor =~ 'fun')
188 call NitOmnifuncAddFromFile(a:base, matches, 'modules.txt')
191 " Classes (instanciable only)
192 if prev_word == 'new'
194 call NitOmnifuncAddFromFile(a:base, matches, 'constructors.txt')
197 " Other class references
198 if count(['class', 'super'], prev_word) > 0
200 call NitOmnifuncAddFromFile(a:base, matches, 'classes.txt')
204 if count(['class', 'super', 'nullable', 'isa', 'as'], prev_word) > 0 ||
205 \ line_prev_cursor =~ '[' || prev_char == ':' ||
206 \ (line_prev_cursor =~ 'fun' && line_prev_cursor =~ 'import' && (prev_word == 'import' || prev_char == ','))
208 call NitOmnifuncAddFromFile(a:base, matches, 'types.txt')
212 if prev_char == '.' || line_prev_cursor =~ '['
214 call NitOmnifuncAddFromFile(a:base, matches, 'properties.txt')
217 " If is nothing else...
219 " It may be a keyword
220 if strlen(a:base) > 0
221 for keyword in ['module', 'import', 'class', 'abstract', 'interface',
222 \'universal', 'enum', 'end', 'fun', 'type', 'init', 'redef', 'is',
223 \'do', 'var', 'extern', 'public', 'protected', 'private', 'intrude',
224 \'if', 'then', 'else', 'while', 'loop', 'for', 'in', 'and', 'or',
225 \'not', 'implies', 'return', 'continue', 'break', 'abort', 'assert',
226 \'new', 'isa', 'once', 'super', 'self', 'true', 'false', 'null',
227 \'as', 'nullable', 'isset', 'label']
229 if keyword =~ '^' . a:base
230 call add(matches, keyword)
235 " it may still be a method call or property access
236 call NitOmnifuncAddFromFile(a:base, matches, 'properties.txt')
239 return {'words': matches, 'refresh': 'always'}
243 " Activate the omnifunc on Nit files
244 autocmd FileType nit set omnifunc=NitOmnifunc
246 let s:script_dir = fnamemodify(resolve(expand('<sfile>:p')), ':h')