Mercurial > vim
annotate runtime/ftplugin/changelog.vim @ 28177:f04a3ec65e2d v8.2.4614
patch 8.2.4614: redrawing too much when 'cursorline' is set
Commit: https://github.com/vim/vim/commit/c20e46a4e3efcd408ef132872238144ea34f7ae5
Author: zeertzjq <zeertzjq@outlook.com>
Date: Wed Mar 23 14:55:23 2022 +0000
patch 8.2.4614: redrawing too much when 'cursorline' is set
Problem: Redrawing too much when 'cursorline' is set and jumping around.
Solution: Rely on win_update() to redraw the current and previous cursor
line, do not mark lines as modified. (closes #9996)
author | Bram Moolenaar <Bram@vim.org> |
---|---|
date | Wed, 23 Mar 2022 16:00:03 +0100 |
parents | ebedba7a4898 |
children | c3c347a71e05 |
rev | line source |
---|---|
7 | 1 " Vim filetype plugin file |
7272
17333ebd2bbd
commit https://github.com/vim/vim/commit/d042dc825c9b97dacd84d4728f88300da4d5b6b9
Christian Brabandt <cb@256bit.org>
parents:
5618
diff
changeset
|
2 " Language: generic Changelog file |
17333ebd2bbd
commit https://github.com/vim/vim/commit/d042dc825c9b97dacd84d4728f88300da4d5b6b9
Christian Brabandt <cb@256bit.org>
parents:
5618
diff
changeset
|
3 " Maintainer: Martin Florian <marfl@posteo.de> |
17333ebd2bbd
commit https://github.com/vim/vim/commit/d042dc825c9b97dacd84d4728f88300da4d5b6b9
Christian Brabandt <cb@256bit.org>
parents:
5618
diff
changeset
|
4 " Previous Maintainer: Nikolai Weibull <now@bitwi.se> |
26050 | 5 " Latest Revision: 2021-10-17 |
7 | 6 " Variables: |
839 | 7 " g:changelog_timeformat (deprecated: use g:changelog_dateformat instead) - |
375 | 8 " description: the timeformat used in ChangeLog entries. |
9 " default: "%Y-%m-%d". | |
839 | 10 " g:changelog_dateformat - |
11 " description: the format sent to strftime() to generate a date string. | |
12 " default: "%Y-%m-%d". | |
7 | 13 " g:changelog_username - |
375 | 14 " description: the username to use in ChangeLog entries |
15 " default: try to deduce it from environment variables and system files. | |
7 | 16 " Local Mappings: |
17 " <Leader>o - | |
375 | 18 " adds a new changelog entry for the current user for the current date. |
7 | 19 " Global Mappings: |
20 " <Leader>o - | |
375 | 21 " switches to the ChangeLog buffer opened for the current directory, or |
22 " opens it in a new buffer if it exists in the current directory. Then | |
23 " it does the same as the local <Leader>o described above. | |
7 | 24 " Notes: |
25 " run 'runtime ftplugin/changelog.vim' to enable the global mapping for | |
26 " changelog files. | |
27 " TODO: | |
28 " should we perhaps open the ChangeLog file even if it doesn't exist already? | |
29 " Problem is that you might end up with ChangeLog files all over the place. | |
30 | |
31 " If 'filetype' isn't "changelog", we must have been to add ChangeLog opener | |
839 | 32 if &filetype == 'changelog' |
33 if exists('b:did_ftplugin') | |
7 | 34 finish |
35 endif | |
36 let b:did_ftplugin = 1 | |
37 | |
375 | 38 let s:cpo_save = &cpo |
39 set cpo&vim | |
7 | 40 |
839 | 41 " Set up the format used for dates. |
42 if !exists('g:changelog_dateformat') | |
43 if exists('g:changelog_timeformat') | |
44 let g:changelog_dateformat = g:changelog_timeformat | |
45 else | |
46 let g:changelog_dateformat = "%Y-%m-%d" | |
47 endif | |
7 | 48 endif |
49 | |
2034 | 50 function! s:username() |
51 if exists('g:changelog_username') | |
52 return g:changelog_username | |
53 elseif $EMAIL != "" | |
54 return $EMAIL | |
55 elseif $EMAIL_ADDRESS != "" | |
56 return $EMAIL_ADDRESS | |
57 endif | |
26050 | 58 |
2034 | 59 let login = s:login() |
60 return printf('%s <%s@%s>', s:name(login), login, s:hostname()) | |
61 endfunction | |
62 | |
63 function! s:login() | |
64 return s:trimmed_system_with_default('whoami', 'unknown') | |
65 endfunction | |
66 | |
67 function! s:trimmed_system_with_default(command, default) | |
68 return s:first_line(s:system_with_default(a:command, a:default)) | |
69 endfunction | |
70 | |
71 function! s:system_with_default(command, default) | |
72 let output = system(a:command) | |
73 if v:shell_error | |
74 return default | |
75 endif | |
76 return output | |
77 endfunction | |
78 | |
79 function! s:first_line(string) | |
80 return substitute(a:string, '\n.*$', "", "") | |
81 endfunction | |
7 | 82 |
2034 | 83 function! s:name(login) |
84 for name in [s:gecos_name(a:login), $NAME, s:capitalize(a:login)] | |
85 if name != "" | |
86 return name | |
7 | 87 endif |
2034 | 88 endfor |
89 endfunction | |
90 | |
91 function! s:gecos_name(login) | |
92 for line in s:try_reading_file('/etc/passwd') | |
93 if line =~ '^' . a:login . ':' | |
94 return substitute(s:passwd_field(line, 5), '&', s:capitalize(a:login), "") | |
95 endif | |
96 endfor | |
97 return "" | |
98 endfunction | |
7 | 99 |
2034 | 100 function! s:try_reading_file(path) |
101 try | |
102 return readfile(a:path) | |
2826 | 103 catch |
104 return [] | |
2034 | 105 endtry |
106 endfunction | |
7 | 107 |
2034 | 108 function! s:passwd_field(line, field) |
109 let fields = split(a:line, ':', 1) | |
3830 | 110 if len(fields) < a:field |
2034 | 111 return "" |
112 endif | |
3830 | 113 return fields[a:field - 1] |
2034 | 114 endfunction |
7 | 115 |
2034 | 116 function! s:capitalize(word) |
117 return toupper(a:word[0]) . strpart(a:word, 1) | |
118 endfunction | |
119 | |
120 function! s:hostname() | |
121 return s:trimmed_system_with_default('hostname', 'localhost') | |
122 endfunction | |
7 | 123 |
839 | 124 " Format used for new date entries. |
125 if !exists('g:changelog_new_date_format') | |
5568 | 126 let g:changelog_new_date_format = "%d %u\n\n\t* %p%c\n\n" |
7 | 127 endif |
128 | |
839 | 129 " Format used for new entries to current date entry. |
130 if !exists('g:changelog_new_entry_format') | |
5568 | 131 let g:changelog_new_entry_format = "\t* %p%c" |
7 | 132 endif |
133 | |
839 | 134 " Regular expression used to find a given date entry. |
135 if !exists('g:changelog_date_entry_search') | |
7 | 136 let g:changelog_date_entry_search = '^\s*%d\_s*%u' |
137 endif | |
138 | |
1213 | 139 " Regular expression used to find the end of a date entry |
140 if !exists('g:changelog_date_end_entry_search') | |
1621 | 141 let g:changelog_date_end_entry_search = '^\s*$' |
1213 | 142 endif |
143 | |
144 | |
839 | 145 " Substitutes specific items in new date-entry formats and search strings. |
146 " Can be done with substitute of course, but unclean, and need \@! then. | |
5568 | 147 function! s:substitute_items(str, date, user, prefix) |
7 | 148 let str = a:str |
5568 | 149 let middles = {'%': '%', 'd': a:date, 'u': a:user, 'p': a:prefix, 'c': '{cursor}'} |
7 | 150 let i = stridx(str, '%') |
151 while i != -1 | |
839 | 152 let inc = 0 |
153 if has_key(middles, str[i + 1]) | |
154 let mid = middles[str[i + 1]] | |
155 let str = strpart(str, 0, i) . mid . strpart(str, i + 2) | |
5618 | 156 let inc = strlen(mid) - 1 |
7 | 157 endif |
839 | 158 let i = stridx(str, '%', i + 1 + inc) |
7 | 159 endwhile |
160 return str | |
161 endfunction | |
162 | |
839 | 163 " Position the cursor once we've done all the funky substitution. |
7 | 164 function! s:position_cursor() |
165 if search('{cursor}') > 0 | |
839 | 166 let lnum = line('.') |
167 let line = getline(lnum) | |
7 | 168 let cursor = stridx(line, '{cursor}') |
839 | 169 call setline(lnum, substitute(line, '{cursor}', '', '')) |
7 | 170 endif |
7272
17333ebd2bbd
commit https://github.com/vim/vim/commit/d042dc825c9b97dacd84d4728f88300da4d5b6b9
Christian Brabandt <cb@256bit.org>
parents:
5618
diff
changeset
|
171 startinsert |
7 | 172 endfunction |
173 | |
839 | 174 " Internal function to create a new entry in the ChangeLog. |
5568 | 175 function! s:new_changelog_entry(prefix) |
839 | 176 " Deal with 'paste' option. |
7 | 177 let save_paste = &paste |
178 let &paste = 1 | |
839 | 179 call cursor(1, 1) |
180 " Look for an entry for today by our user. | |
181 let date = strftime(g:changelog_dateformat) | |
7 | 182 let search = s:substitute_items(g:changelog_date_entry_search, date, |
5568 | 183 \ s:username(), a:prefix) |
7 | 184 if search(search) > 0 |
839 | 185 " Ok, now we look for the end of the date entry, and add an entry. |
186 call cursor(nextnonblank(line('.') + 1), 1) | |
1213 | 187 if search(g:changelog_date_end_entry_search, 'W') > 0 |
2034 | 188 let p = (line('.') == line('$')) ? line('.') : line('.') - 1 |
839 | 189 else |
190 let p = line('.') | |
191 endif | |
5568 | 192 let ls = split(s:substitute_items(g:changelog_new_entry_format, '', '', a:prefix), |
839 | 193 \ '\n') |
194 call append(p, ls) | |
195 call cursor(p + 1, 1) | |
7 | 196 else |
839 | 197 " Flag for removing empty lines at end of new ChangeLogs. |
7 | 198 let remove_empty = line('$') == 1 |
199 | |
839 | 200 " No entry today, so create a date-user header and insert an entry. |
7 | 201 let todays_entry = s:substitute_items(g:changelog_new_date_format, |
5568 | 202 \ date, s:username(), a:prefix) |
839 | 203 " Make sure we have a cursor positioning. |
7 | 204 if stridx(todays_entry, '{cursor}') == -1 |
839 | 205 let todays_entry = todays_entry . '{cursor}' |
7 | 206 endif |
207 | |
839 | 208 " Now do the work. |
209 call append(0, split(todays_entry, '\n')) | |
5568 | 210 |
839 | 211 " Remove empty lines at end of file. |
7 | 212 if remove_empty |
839 | 213 $-/^\s*$/-1,$delete |
7 | 214 endif |
215 | |
839 | 216 " Reposition cursor once we're done. |
217 call cursor(1, 1) | |
7 | 218 endif |
219 | |
220 call s:position_cursor() | |
221 | |
222 " And reset 'paste' option | |
223 let &paste = save_paste | |
224 endfunction | |
225 | |
839 | 226 let b:undo_ftplugin = "setl com< fo< et< ai<" |
7 | 227 |
228 setlocal comments= | |
229 setlocal formatoptions+=t | |
230 setlocal noexpandtab | |
375 | 231 setlocal autoindent |
7 | 232 |
839 | 233 if &textwidth == 0 |
234 setlocal textwidth=78 | |
235 let b:undo_ftplugin .= " tw<" | |
236 endif | |
237 | |
26050 | 238 if !exists("no_plugin_maps") && !exists("no_changelog_maps") && exists(":NewChangelogEntry") != 2 |
239 nnoremap <buffer> <silent> <Leader>o :<C-u>call <SID>new_changelog_entry('')<CR> | |
240 xnoremap <buffer> <silent> <Leader>o :<C-u>call <SID>new_changelog_entry('')<CR> | |
241 command! -buffer -nargs=0 NewChangelogEntry call s:new_changelog_entry('') | |
242 let b:undo_ftplugin .= " | sil! exe 'nunmap <buffer> <Leader>o'" . | |
243 \ " | sil! exe 'vunmap <buffer> <Leader>o'" . | |
244 \ " | sil! delc NewChangelogEntry" | |
245 endif | |
246 | |
375 | 247 let &cpo = s:cpo_save |
248 unlet s:cpo_save | |
7 | 249 else |
2034 | 250 let s:cpo_save = &cpo |
251 set cpo&vim | |
252 | |
26050 | 253 if !exists("no_plugin_maps") && !exists("no_changelog_maps") |
254 " Add the Changelog opening mapping | |
255 nnoremap <silent> <Leader>o :call <SID>open_changelog()<CR> | |
256 let b:undo_ftplugin .= " | silent! exe 'nunmap <buffer> <Leader>o" | |
257 endif | |
7 | 258 |
259 function! s:open_changelog() | |
2034 | 260 let path = expand('%:p:h') |
261 if exists('b:changelog_path') | |
262 let changelog = b:changelog_path | |
263 else | |
264 if exists('b:changelog_name') | |
265 let name = b:changelog_name | |
266 else | |
267 let name = 'ChangeLog' | |
268 endif | |
269 while isdirectory(path) | |
270 let changelog = path . '/' . name | |
271 if filereadable(changelog) | |
272 break | |
273 endif | |
274 let parent = substitute(path, '/\+[^/]*$', "", "") | |
275 if path == parent | |
276 break | |
277 endif | |
278 let path = parent | |
279 endwhile | |
280 endif | |
281 if !filereadable(changelog) | |
839 | 282 return |
283 endif | |
2034 | 284 |
285 if exists('b:changelog_entry_prefix') | |
286 let prefix = call(b:changelog_entry_prefix, []) | |
287 else | |
5568 | 288 let prefix = substitute(strpart(expand('%:p'), strlen(path)), '^/\+', "", "") |
2034 | 289 endif |
290 | |
291 let buf = bufnr(changelog) | |
839 | 292 if buf != -1 |
293 if bufwinnr(buf) != -1 | |
1213 | 294 execute bufwinnr(buf) . 'wincmd w' |
7 | 295 else |
1213 | 296 execute 'sbuffer' buf |
7 | 297 endif |
839 | 298 else |
2034 | 299 execute 'split' fnameescape(changelog) |
839 | 300 endif |
7 | 301 |
2034 | 302 call s:new_changelog_entry(prefix) |
7 | 303 endfunction |
2034 | 304 |
305 let &cpo = s:cpo_save | |
306 unlet s:cpo_save | |
7 | 307 endif |