diff options
| author | Adam Stankiewicz <sheerun@sher.pl> | 2013-09-12 17:32:53 +0200 | 
|---|---|---|
| committer | Adam Stankiewicz <sheerun@sher.pl> | 2013-09-12 17:32:53 +0200 | 
| commit | 5bc380150aee647d26a5a538ed855e9e82dcc7f7 (patch) | |
| tree | ccefa37a6445e393eed12719509f830eae513e3a /autoload | |
| parent | 6eb0c57e8070d641382c8844d35408a2f13cc751 (diff) | |
| download | vim-polyglot-5bc380150aee647d26a5a538ed855e9e82dcc7f7.tar.gz vim-polyglot-5bc380150aee647d26a5a538ed855e9e82dcc7f7.zip | |
Add erlang support
Diffstat (limited to 'autoload')
| -rw-r--r-- | autoload/erlang_complete.vim | 219 | 
1 files changed, 219 insertions, 0 deletions
| diff --git a/autoload/erlang_complete.vim b/autoload/erlang_complete.vim new file mode 100644 index 00000000..9d108fbc --- /dev/null +++ b/autoload/erlang_complete.vim @@ -0,0 +1,219 @@ +" Vim omni completion file +" Language:     Erlang +" Author:       Oscar Hellström <oscar@oscarh.net> +" Contributors: kTT (http://github.com/kTT) +"               Ricardo Catalinas Jiménez <jimenezrick@gmail.com> +"               Eduardo Lopez (http://github.com/tapichu) +"               Zhihui Jiao (http://github.com/onlychoice) +" License:      Vim license +" Version:      2012/11/26 + +if !exists('g:erlang_completion_cache') +	let g:erlang_completion_cache = 1 +endif + +" Completion program path +let s:erlang_complete_file = expand('<sfile>:p:h') . '/erlang_complete.erl' + +" Modules cache used to speed up the completion +let s:modules_cache = {} + +" File cache for persistence between Vim sessions +if filewritable(expand('<sfile>:p:h')) == 2 +	let s:file_cache = expand('<sfile>:p:h') . '/vimerl_cache' +else +	let s:file_cache = '/tmp/vimerl_cache' +endif + +" Patterns for completions +let s:erlang_local_func_beg    = '\(\<[0-9A-Za-z_-]*\|\s*\)$' +let s:erlang_external_func_beg = '\<[0-9A-Za-z_-]\+:[0-9A-Za-z_-]*$' +let s:erlang_blank_line        = '^\s*\(%.*\)\?$' + +" Main function for completion +function erlang_complete#Complete(findstart, base) +	let lnum = line('.') +	let column = col('.') +	let line = strpart(getline('.'), 0, column - 1) + +	" 1) Check if the char to the left of us are part of a function call +	" +	" Nothing interesting is written at the char just before the cursor +	" This means _anything_ could be started here +	" In this case, keyword completion should probably be used, +	" for now we'll only try and complete local functions. +	" +	" TODO: Examine if we can stare Identifiers end complete on them +	" Is this worth it? Is /completion/ of a "blank" wanted? Can we consider +	" `(' interesting and check if we are in a function call etc.? +	if line[column - 2] !~ '[0-9A-Za-z:_-]' +		if a:findstart +			return column +		else +			return s:ErlangFindLocalFunc(a:base) +		endif +	endif +	 +	" 2) Function in external module +	if line =~ s:erlang_external_func_beg +		let delimiter = match(line, ':[0-9A-Za-z_-]*$') + 1 +		if a:findstart +			return delimiter +		else +			let module = matchstr(line[:-2], '\<\k*\>$') +			return s:ErlangFindExternalFunc(module, a:base) +		endif +	endif + +	" 3) Local function +	if line =~ s:erlang_local_func_beg +		let funcstart = match(line, ':\@<![0-9A-Za-z_-]*$') +		if a:findstart +			return funcstart +		else +			return s:ErlangFindLocalFunc(a:base) +		endif +	endif + +	" 4) Unhandled situation +	if a:findstart +		return -1 +	else +		return [] +	endif +endfunction + +" Find the next non-blank line +function s:ErlangFindNextNonBlank(lnum) +	let lnum = nextnonblank(a:lnum + 1) +	let line = getline(lnum) + +	while line =~ s:erlang_blank_line && 0 != lnum +		let lnum = nextnonblank(lnum + 1) +		let line = getline(lnum) +	endwhile + +	return lnum +endfunction + +" Find external function names +function s:ErlangFindExternalFunc(module, base) +	" If the module is cached, load its functions +	if has_key(s:modules_cache, a:module) +		for field_cache in get(s:modules_cache, a:module) +			if match(field_cache.word, a:base) == 0 +				call complete_add(field_cache) +			endif +		endfor + +		return [] +	endif + +	let functions = system(s:erlang_complete_file . ' ' . a:module) +	for function_spec in split(functions, '\n') +		if match(function_spec, a:base) == 0 +			let function_name = matchstr(function_spec, a:base . '\w*') +			let field = {'word': function_name . '(', 'abbr': function_spec, +				  \  'kind': 'f', 'dup': 1} +			call complete_add(field) + +			" Populate the cache only when iterating over all the +			" module functions (i.e. no prefix for the completion) +			if g:erlang_completion_cache && a:base == '' +				if !has_key(s:modules_cache, a:module) +					let s:modules_cache[a:module] = [field] +				else +					let fields_cache = get(s:modules_cache, a:module) +					let s:modules_cache[a:module] = add(fields_cache, field) +				endif +			endif + +			" The user entered some text, so stop the completion +			if complete_check() +				" The module couldn't be entirely cached +				if has_key(s:modules_cache, a:module) +					call remove(s:modules_cache, a:module) +				endif +				break +			endif +		endif +	endfor + +	call s:ErlangWriteCache(a:module) + +	return [] +endfunction + +" Find local function names +function s:ErlangFindLocalFunc(base) +	" Begin at line 1 +	let lnum = s:ErlangFindNextNonBlank(1) + +	if "" == a:base +		let base = '\w' " Used to match against word symbol +	else +		let base = a:base +	endif + +	while 0 != lnum && !complete_check() +		let line = getline(lnum) +		let function_name = matchstr(line, '^' . base . '[0-9A-Za-z_-]\+(\@=') +		if function_name != "" +			call complete_add({'word': function_name, 'kind': 'f'}) +		endif +		let lnum = s:ErlangFindNextNonBlank(lnum) +	endwhile + +	return [] +endfunction + +function s:ErlangLoadCache() +	if filereadable(s:file_cache) +		for line in readfile(s:file_cache) +			let cache_entry = eval(line) +			" cache_entry is a dict with just one key with the +			" module name and the function list we are going to +			" add to the memory cache as the value of this key +			for mod_name in keys(cache_entry) +				let func_list = get(cache_entry, mod_name) +				let s:modules_cache[mod_name] = func_list +			endfor +		endfor +	endif +endfunction + +function s:ErlangWriteCache(module) +	" Write all the module functions to the cache file +	if has_key(s:modules_cache, a:module) +		let func_list = get(s:modules_cache, a:module) +		if len(func_list) > 0 +			let cache_entry = {a:module : func_list} +			execute 'redir >>' . s:file_cache +			silent echon cache_entry +			silent echon "\n" +			redir END +		endif +	endif +endfunction + +function s:ErlangPurgeCache(...) +	for mod_name in a:000 +		if has_key(s:modules_cache, mod_name) +			call remove(s:modules_cache, mod_name) +		endif +	endfor + +	" Delete the old cache file +	call delete(s:file_cache) + +	" Write a new one +	for mod_name in keys(s:modules_cache) +		call s:ErlangWriteCache(mod_name) +	endfor +endfunction + +" Load the file cache when this script is autoloaded +call s:ErlangLoadCache() + +" Command for removing modules from the cache +command -nargs=+ ErlangPurgeCache silent call s:ErlangPurgeCache(<f-args>) | 
