summaryrefslogtreecommitdiffstats
path: root/ftplugin/erlang.vim
blob: 4f1acfe8eee0cab25b7038d92845b67d38def87e (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
" Vim ftplugin file
" Language:    Erlang
" Maintainer:  Oscar Hellström <oscar@oscarh.net>
" URL:         http://personal.oscarh.net
" Contributor: Ricardo Catalinas Jiménez <jimenezrick@gmail.com>
" Version:     2010-09-03
" ------------------------------------------------------------------------------
" Usage:
"
" To enable folding put in your vimrc:
" set foldenable
"
" Folding will make only one fold for a complete function, even though it has
" more than one function head and body.
"
" To change this behaviour put in your vimrc file:
" let g:erlangFoldSplitFunction=1
"
" ------------------------------------------------------------------------------
" Plugin init
if exists("b:did_ftplugin")
	finish
endif

" Don't load any other
let b:did_ftplugin=1

if exists('s:doneFunctionDefinitions')
	call s:SetErlangOptions()
	finish
endif

let s:doneFunctionDefinitions=1

" Local settings
function s:SetErlangOptions()
	compiler erlang
	if version >= 700
		setlocal omnifunc=erlangcomplete#Complete
	endif

	setlocal comments=:%%%,:%%,:%
	setlocal commentstring=%%s

	setlocal foldmethod=expr
	setlocal foldexpr=GetErlangFold(v:lnum)
	setlocal foldtext=ErlangFoldText()
endfunction

" Define folding functions
if !exists("*GetErlangFold")
	" Folding params
	let s:ErlangFunBegin    = '^\a\w*(.*$'
	let s:ErlangFunEnd      = '^[^%]*\.\s*\(%.*\)\?$'
	let s:ErlangBlankLine   = '^\s*\(%.*\)\?$'

	" Auxiliary fold functions
	function s:GetNextNonBlank(lnum)
		let lnum = nextnonblank(a:lnum + 1)
		let line = getline(lnum)
		while line =~ s:ErlangBlankLine && 0 != lnum
			let lnum = nextnonblank(lnum + 1)
			let line = getline(lnum)
		endwhile
		return lnum
	endfunction

	function s:GetFunName(str)
		return matchstr(a:str, '^\a\w*(\@=')
	endfunction

	function s:GetFunArgs(str, lnum)
		let str = a:str
		let lnum = a:lnum
		while str !~ '->\s*\(%.*\)\?$'
			let lnum = s:GetNextNonBlank(lnum)
			if 0 == lnum " EOF
				return ""
			endif
			let str .= getline(lnum)
		endwhile
		return matchstr(str, 
			\ '\(^(\s*\)\@<=.*\(\s*)\(\s\+when\s\+.*\)\?\s\+->\s*\(%.*\)\?$\)\@=')
	endfunction

	function s:CountFunArgs(arguments)
		let pos = 0
		let ac = 0 " arg count
		let arguments = a:arguments
		
		" Change list / tuples into just one A(rgument)
		let erlangTuple = '{\([A-Za-z_,|=\-\[\]]\|\s\)*}'
		let erlangList  = '\[\([A-Za-z_,|=\-{}]\|\s\)*\]'

		" FIXME: Use searchpair?
		while arguments =~ erlangTuple
			let arguments = substitute(arguments, erlangTuple, "A", "g")
		endwhile
		" FIXME: Use searchpair?
		while arguments =~ erlangList
			let arguments = substitute(arguments, erlangList, "A", "g")
		endwhile
		
		let len = strlen(arguments)
		while pos < len && pos > -1
			let ac += 1
			let pos = matchend(arguments, ',\s*', pos)
		endwhile
		return ac
	endfunction

	" Main fold function
	function GetErlangFold(lnum)
		let lnum = a:lnum
		let line = getline(lnum)

		if line =~ s:ErlangFunEnd
			return '<1'
		endif

		if line =~ s:ErlangFunBegin && foldlevel(lnum - 1) == 1
			if exists("g:erlangFoldSplitFunction") && g:erlangFoldSplitFunction
				return '>1'
			else
				return '1'
			endif
		endif

		if line =~ s:ErlangFunBegin
			return '>1'
		endif

		return '='
	endfunction

	" Erlang fold description (foldtext function)
	function ErlangFoldText()
		let foldlen = v:foldend - v:foldstart
		if 1 < foldlen
			let lines = "lines"
		else
			let lines = "line"
		endif
		let line = getline(v:foldstart)
		let name = s:GetFunName(line)
		let arguments = s:GetFunArgs(strpart(line, strlen(name)), v:foldstart)
		let argcount = s:CountFunArgs(arguments)
		let retval = "+" . v:folddashes . " " . name . "/" . argcount
		let retval .= " (" . foldlen . " " . lines . ")"
		return retval
	endfunction
endif

call s:SetErlangOptions()