forked from dilawar/vim
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathformat_comment.vim
247 lines (210 loc) · 7.97 KB
/
format_comment.vim
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
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
" Format-block (do a 'gq' format) on the comment the cursor is in; the type of
" comment is determined by context (i.e., /*...*/, //..., #..., etc.).
"
" EXAMPLE SETUP
" map gqc :call FormatComment()<CR>
" $Header: /home/common/vim/autoload/RCS/FormatComment.vim,v 1.4 2002/04/30 16:16:53 gary Exp $
source $HOME/.vim/scripts/format_block.vim
function! FormatComment()
let current_line = getline(".")
if (match(current_line, '^\s*\/\=\*') >= 0) "}{
" C-style /*...*/ comment (single-line or multi-line).
if match(current_line, '^\s*\/\*\([^*\\]\|\\.\|\*\(\/\)\@!\)*\*\/\s*$') >= 0 "{
" Single-line /*...*/ comment; check for some special cases...
" Don't mess with 'divider' comments; i.e., all ='s -'s, *'s, etc.
if match(current_line, '^\s*\/\*[ *_=-]\+\*\/\s*$') >= 0
echohl WarningMsg
echo 'This appears to be a correctly formatted "divider" comment.'
echohl None
call s:RingBell()
return
endif
" Appears to be a 'normal' one-line comment; format it.
normal! gqq
else "}{
" Multi-line C-style: /* This is a
" * multi-line
" * comment.
" */
"
" See if this is a standard-style function-header comment; if
" so, handle it specially; otherwise use the FormatBlock
" function to locate the endpoints, and do the formatting.
"
if (match(current_line, '^\s*\/\*') >= 0)
let start_line = line(".")
else
let start_line = search('^\s*\/\*', 'bW')
endif
if (start_line > 0 && match(getline(start_line + 1), '^\s*\*.*FUNCTION:') >= 0)
" This appears to be a standard function-header comment;
" carefully apply gqq to the separate sections of the
" comment soas not to collapse too much.
"
exe start_line
while (match(getline("."), '\*/') < 0) " {
if match(getline("."), '^ \* [A-Z ]\+:') >= 0 "{
if match(getline("."), '^ \* RETURNS:') >= 0 && match(getline(line(".") + 1), '^ \*\s\+\S\+\t') >= 0 "{
" Once we hit the RETURNS section (and the
" next line contains a tab), get out;
" generally, applying gqq to that area would
" mess it up (since the text describing each
" return value is normally indented so that
" the return values form a vertical column).
"
" We skip to the end of the comment instead
" of just breaking the loop so that the
" cursor ends up at the end of the comment
" instead of sitting on the "RETURNS:" line.
"
let start_line = line(".")
while match(getline(start_line + 1), '\*\/') < 0
let start_line = start_line + 1
endwhile
exe start_line
endif "}
" Section heading (e.g., FUNCTION: or MODIFIES:);
" skip this line.
let start_line = line(".") + 1
exe start_line
else "}{
exe "normal! gq\r"
endif "}
endwhile "}
else
call FormatBlock('^\s*\/\*',
\'^\s*\([^*\\]\|\\.\|\*\(\/\)\@!\)*\*\/',
\'^\(\s*\/\*\)\@!\([^*\\]\|\\.\|\*\(\/\)\@!\)*$')
endif
endif "}
" We're normally left on the last line of the comment after the
" formatting operation; see what it looks like, and do some cleanup
" if needed.
"
if match(getline("."), '^\s*\*\s\+\*\/\s*$') >= 0 "{
" The comment ended up looking like:
"
" /* This is a multi-line
" * comment.
" * */
"
" Get rid of the extra '*'.
s#\*\s\+\*/\s*$#*/#
elseif match(getline("."), '^\s*\*.*\*\/\s*$') >= 0 "}{
" The comment ended up looking like:
"
" /* This is a multi-line
" * comment. */
"
" put the trailing '*/' on its own line.
"
s#\s*\*/\s*$#*/#
normal! yyP$F*Dj$F*d0==
endif "}
" Finally, if the comment is down to a single line (or two lines
" where the second line only contains the comment's closing '*/'),
" turn it into a single-line '//'-style comment.
"
if ( match(getline("."), '^\s*\/\*') >= 0
\|| ( match(getline( "." ), '^\s*\*\/') >= 0
\ && match(getline(line(".") - 1), '^\s*\/\*') >= 0))
call s:ToSingleLineComment()
endif
elseif (match(current_line, '^\s*//') >= 0) "}{
" C-style //... comment.
call FormatBlock('^\s*\([^/ \t]\|$\)?+1', '^\s*\([^/ \t]\|$\)/-1', '^\s*//')
if match(getline(line(".") - 1), '^\s*\/\/') >= 0
call s:ToMultiLineComment()
endif
elseif (match(current_line, '^\s*#') >= 0) "}{
" Shell/Perl style #... comment.
call FormatBlock('^\s*\([^# \t]\|$\)?+1', '^\s*\([^# \t]\|$\)/-1', '^\s*#')
elseif (match(current_line, '^\s*"') >= 0) "}{
" Vim-script style "... comment.
call FormatBlock('^\s*\([^" \t]\|$\)?+1', '^\s*\([^" \t]\|$\)/-1', '^\s*"')
else "}{
" Can't figure out what kind of comment we're in.
echohl WarningMsg | echo "Don't appear to be on a formattable comment." | echohl None
call s:RingBell()
endif "}
endfunction
" ==============================================================================
" Change a single-line comment like:
" /* foo */
"
" or a two-line comment like
"
" /* This is a comment
" */
"
" into a single-line '//' comment.
function! s:ToSingleLineComment()
let start_line = line(".")
if match(getline(start_line), '^\s*\/\*\([^*\\]\|\\.\)*\*\/\s*$') >= 0
" A complete /* foo */ comment on one line.
s#^\(\s*\)/\*\(.\{-}\)\s*\*/#\1//\2#
return
endif
let start_pat = '^\s*\/\*'
let end_pat = '^\s*\*\/\s*$'
if match(getline(start_line), start_pat) >= 0
" On a line starting with '/*'; assume the following line starts with '*/'.
let end_line = start_line + 1
elseif match(getline(start_line), end_pat) >= 0
" On a line starting with '*/'; assume the preceding line starts with '/*'.
let end_line = start_line
let start_line = end_line - 1
endif
" Make sure start_line starts with '/*', and end_line starts with '*/'.
if match(getline(start_line), start_pat) == -1 || match(getline(end_line), end_pat) == -1
echohl WarningMsg | echo 'Cannot single-line this comment.' | call s:RingBell() | echohl None
return
endif
exe end_line
normal! ddk
exe g:silent . 's#^\(\s*\)/\*\(.\{-}\)\s*$#\1//\2#'
endfunction
" ==============================================================================
" Change a multi-line '// ...' comment into a /* ...
" * ...
" */ comment.
function! s:ToMultiLineComment()
let start_line = line(".")
if (match(getline(start_line), '^\s*\/\/') == -1)
echohl WarningMsg | echo 'Not in a multi-line "//" comment.' | call s:RingBell() | echohl None
return
endif
let end_line = start_line
while (match(getline(start_line - 1), '^\s*\/\/') >= 0)
let start_line = start_line - 1
endwhile
while (match(getline(end_line + 1), '^\s*\/\/') >= 0)
let end_line = end_line + 1
endwhile
if (start_line == end_line)
echohl WarningMsg | echo 'This is a one-line "//" comment.' | call s:RingBell() | echohl None
return
endif
if (match(getline(end_line), '^\s*\/\/\s*$') >= 0)
" The last line is just a '//' so we want to replace it with ' */'
" instead of replacing it with ' *', and adding a new terminating '*/'
" line.
exe end_line
exe g:silent . 's#//# */#'
let end_line = end_line - 1
else
exe end_line + 1
normal! O */
endif
exe start_line
exe g:silent . 's#//#/*#'
exe g:silent . (start_line + 1) . ',' . end_line . 's#^\(\s*\)//#\1 *#'
exe end_line + 1
endfunction
" ==============================================================================
function! s:RingBell()
if &errorbells
normal! \<Esc>
endif
endfunction
" ==============================================================================