]>
Commit | Line | Data |
---|---|---|
f993e922 | 1 | " Modeliner |
2 | " | |
3 | " Version: 0.3.0 | |
4 | " Description: | |
5 | " | |
6 | " Generates a modeline from current settings. | |
7 | " | |
8 | " Last Change: 27-Jun-2008. | |
9 | " Maintainer: Shuhei Kubota <chimachima@gmail.com> | |
10 | " | |
11 | " Usage: | |
12 | " execute ':Modeliner'. | |
13 | " Then a modeline is generated. | |
14 | " | |
15 | " The modeline will either be appended next to the current line or replace | |
16 | " the existing one. | |
17 | " | |
18 | " If you want to customize option, modify g:Modeliner_format. | |
19 | ||
20 | if !exists('g:Modeliner_format') | |
21 | let g:Modeliner_format = 'et ff= fenc= sts= sw= ts=' | |
22 | " /[ ,:]/ delimited. | |
23 | " | |
24 | " if the type of a option is NOT 'boolean' (see :help 'option-name'), | |
25 | " append '=' to the end of each option. | |
26 | endif | |
27 | ||
28 | ||
29 | "[text] vi: tw=80 noai | |
30 | "[text] vim:tw=80 noai | |
31 | " ex:tw=80 : noai: | |
32 | " | |
33 | "[text] vim: set tw=80 noai:[text] | |
34 | "[text] vim: se tw=80 noai:[text] | |
35 | "[text] vim:set tw=80 noai:[text] | |
36 | " vim: set tw=80 noai: [text] | |
37 | " vim:se tw=80 noai: | |
38 | ||
39 | ||
40 | command! Modeliner call <SID>Modeliner_execute() | |
41 | ||
42 | ||
43 | " to retrieve the position | |
44 | let s:Modeline_SEARCH_PATTERN = '\svi:\|vim:\|ex:' | |
45 | " to extract options from existing modeline | |
46 | let s:Modeline_EXTRACT_PATTERN = '\v(.*)\s+(vi|vim|ex):\s*(set?\s+)?(.+)' " very magic | |
47 | " first form | |
48 | "let s:Modeline_EXTRACT_OPTPATTERN1 = '\v(.+)' " very magic | |
49 | " second form | |
50 | let s:Modeline_EXTRACT_OPTPATTERN2 = '\v(.+):(.*)' " very magic | |
51 | ||
52 | ||
53 | function! s:Modeliner_execute() | |
54 | let options = [] | |
55 | ||
56 | " find existing modeline, and determine the insert position | |
57 | let info = s:SearchExistingModeline() | |
58 | ||
59 | " parse g:Modeliner_format and join options with them | |
60 | let extractedOptStr = g:Modeliner_format . ' ' . info.optStr | |
61 | let extractedOptStr = substitute(extractedOptStr, '[ ,:]\+', ' ', 'g') | |
62 | let extractedOptStr = substitute(extractedOptStr, '=\S*', '=', 'g') | |
63 | let extractedOptStr = substitute(extractedOptStr, 'no\(.\+\)', '\1', 'g') | |
64 | let opts = sort(split(extractedOptStr)) | |
65 | "echom 'opt(list): ' . join(opts, ', ') | |
66 | ||
67 | let optStr = '' | |
68 | let prevO = '' | |
69 | for o in opts | |
70 | if o == prevO | continue | endif | |
71 | let prevO = o | |
72 | ||
73 | if stridx(o, '=') != -1 | |
74 | " let optExpr = 'ts=' . &ts | |
75 | execute 'let optExpr = "' . o . '" . &' . strpart(o, 0, strlen(o) - 1) | |
76 | else | |
77 | " let optExpr = (&et ? '' : 'no') . 'et' | |
78 | execute 'let optExpr = (&' . o . '? "" : "no") . "' . o . '"' | |
79 | endif | |
80 | ||
81 | let optStr = optStr . ' ' . optExpr | |
82 | endfor | |
83 | ||
84 | if info.lineNum == 0 | |
85 | let modeline = s:Commentify(optStr) | |
86 | else | |
87 | let modeline = info.firstText . ' vim: set' . optStr . ' :' . info.lastText | |
88 | endif | |
89 | ||
90 | ||
91 | " insert new modeline | |
92 | if info.lineNum != 0 | |
93 | "modeline FOUND -> replace the modeline | |
94 | ||
95 | "show the existing modeline | |
96 | let orgLine = line('.') | |
97 | let orgCol = col('.') | |
98 | call cursor(info.lineNum, 1) | |
99 | normal V | |
100 | redraw | |
101 | ||
102 | "confirm | |
103 | "if confirm('Are you sure to overwrite this existing modeline?', "&Yes\n&No", 1) == 1 | |
104 | echo 'Are you sure to overwrite this existing modeline? [y/N]' | |
105 | if char2nr(tolower(nr2char(getchar()))) == char2nr('y') | |
106 | call setline(info.lineNum, modeline) | |
107 | ||
108 | "show the modeline being changed | |
109 | if (info.lineNum != line('.')) && (info.lineNum != line('.') + 1) | |
110 | redraw | |
111 | sleep 1 | |
112 | endif | |
113 | endif | |
114 | ||
115 | "back to the previous position | |
116 | echo | |
117 | execute "normal \<ESC>" | |
118 | call cursor(orgLine, orgCol) | |
119 | else | |
120 | "modeline NOT found -> append new modeline | |
121 | call append('.', modeline) | |
122 | endif | |
123 | ||
124 | endfunction | |
125 | ||
126 | ||
127 | function! s:Commentify(s) | |
128 | if exists('g:NERDMapleader') " NERDCommenter | |
129 | let result = b:left . ' vim: set' . a:s . ' : ' . b:right | |
130 | else | |
131 | let result = substitute(&commentstring, '%s', ' vim: set' . a:s . ' : ', '') | |
132 | endif | |
133 | ||
134 | return result | |
135 | endfunction | |
136 | ||
137 | ||
138 | function! s:SearchExistingModeline() | |
139 | let info = {'lineNum':0, 'text':'', 'firstText':'', 'lastText':'', 'optStr':''} | |
140 | ||
141 | let candidates = [] | |
142 | ||
143 | " cursor position? | |
144 | call add(candidates, line('.')) | |
145 | " user may position the cursor to previous line... | |
146 | call add(candidates, line('.') + 1) | |
147 | let cnt = 0 | |
148 | while cnt < &modelines | |
149 | " header? | |
150 | call add(candidates, cnt + 1) | |
151 | " footer? | |
152 | call add(candidates, line('$') - cnt) | |
153 | let cnt = cnt + 1 | |
154 | endwhile | |
155 | ||
156 | " search | |
157 | for i in candidates | |
158 | let lineNum = i | |
159 | let text = getline(lineNum) | |
160 | ||
161 | if match(text, s:Modeline_SEARCH_PATTERN) != -1 | |
162 | let info.lineNum = lineNum | |
163 | let info.text = text | |
164 | break | |
165 | endif | |
166 | endfor | |
167 | ||
168 | " extract texts | |
169 | if info.lineNum != 0 | |
170 | "echom 'modeline: ' info.lineNum . ' ' . info.text | |
171 | ||
172 | let info.firstText = substitute(info.text, s:Modeline_EXTRACT_PATTERN, '\1', '') | |
173 | ||
174 | let isSecondForm = (strlen(substitute(info.text, s:Modeline_EXTRACT_PATTERN, '\3', '')) != 0) | |
175 | "echom 'form : ' . string(isSecondForm + 1) | |
176 | if isSecondForm == 0 | |
177 | let info.lastText = '' | |
178 | let info.optStr = substitute(info.text, s:Modeline_EXTRACT_PATTERN, '\4', '') | |
179 | else | |
180 | let info.lastText = substitute( | |
181 | \ substitute(info.text, s:Modeline_EXTRACT_PATTERN, '\4', ''), | |
182 | \ s:Modeline_EXTRACT_OPTPATTERN2, | |
183 | \ '\2', | |
184 | \ '') | |
185 | let info.optStr = substitute( | |
186 | \ substitute(info.text, s:Modeline_EXTRACT_PATTERN, '\4', ''), | |
187 | \ s:Modeline_EXTRACT_OPTPATTERN2, | |
188 | \ '\1', | |
189 | \ '') | |
190 | endif | |
191 | endif | |
192 | ||
193 | "echom 'firstText: ' . info.firstText | |
194 | "echom 'lastText: ' . info.lastText | |
195 | "echom 'optStr: ' . info.optStr | |
196 | ||
197 | return info | |
198 | endfunction | |
199 | ||
200 | ||
201 | function! s:ExtractOptionStringFromModeline(text) | |
202 | let info = {} | |
203 | ||
204 | let info.firstText = substitute(a:text, s:Modeline_EXTRACT_PATTERN, '\1', '') | |
205 | ||
206 | let isSecondForm = (strlen(substitute(a:text, s:Modeline_EXTRACT_PATTERN, '\3', '') != 0) | |
207 | if isSecondForm == 0 | |
208 | let info.lastText = '' | |
209 | let info.optStr = substitute(a:text, s:Modeline_EXTRACT_PATTERN, '\2', '') | |
210 | else | |
211 | let info.lastText = substitute( | |
212 | \ substitute(a:text, s:Modeline_EXTRACT_PATTERN, '\4', ''), | |
213 | \ s:Modeline_EXTRACT_OPTPATTERN2, | |
214 | \ '\2', | |
215 | \ '') | |
216 | let info.optStr = substitute( | |
217 | \ substitute(a:text, s:Modeline_EXTRACT_PATTERN, '\4', ''), | |
218 | \ s:Modeline_EXTRACT_OPTPATTERN2, | |
219 | \ '\1', | |
220 | \ '') | |
221 | endif | |
222 | ||
223 | return info | |
224 | endfunction | |
225 | ||
226 | " vim: set et fenc=utf-8 ff=unix sts=4 sw=4 ts=4 : |