1071d4279SBram Moolenaar" Vim filetype plugin file 2071d4279SBram Moolenaar" Language: generic Changelog file 3*57657d85SBram Moolenaar" Maintainer: Nikolai Weibull <[email protected]> 4*57657d85SBram Moolenaar" Latest Revision: 2006-04-19 5071d4279SBram Moolenaar" Variables: 6*57657d85SBram Moolenaar" g:changelog_timeformat (deprecated: use g:changelog_dateformat instead) - 7071d4279SBram Moolenaar" description: the timeformat used in ChangeLog entries. 8071d4279SBram Moolenaar" default: "%Y-%m-%d". 9*57657d85SBram Moolenaar" g:changelog_dateformat - 10*57657d85SBram Moolenaar" description: the format sent to strftime() to generate a date string. 11*57657d85SBram Moolenaar" default: "%Y-%m-%d". 12071d4279SBram Moolenaar" g:changelog_username - 13071d4279SBram Moolenaar" description: the username to use in ChangeLog entries 14071d4279SBram Moolenaar" default: try to deduce it from environment variables and system files. 15071d4279SBram Moolenaar" Local Mappings: 16071d4279SBram Moolenaar" <Leader>o - 17071d4279SBram Moolenaar" adds a new changelog entry for the current user for the current date. 18071d4279SBram Moolenaar" Global Mappings: 19071d4279SBram Moolenaar" <Leader>o - 20071d4279SBram Moolenaar" switches to the ChangeLog buffer opened for the current directory, or 21071d4279SBram Moolenaar" opens it in a new buffer if it exists in the current directory. Then 22071d4279SBram Moolenaar" it does the same as the local <Leader>o described above. 23071d4279SBram Moolenaar" Notes: 24071d4279SBram Moolenaar" run 'runtime ftplugin/changelog.vim' to enable the global mapping for 25071d4279SBram Moolenaar" changelog files. 26071d4279SBram Moolenaar" TODO: 27071d4279SBram Moolenaar" should we perhaps open the ChangeLog file even if it doesn't exist already? 28071d4279SBram Moolenaar" Problem is that you might end up with ChangeLog files all over the place. 29071d4279SBram Moolenaar 30071d4279SBram Moolenaar" If 'filetype' isn't "changelog", we must have been to add ChangeLog opener 31*57657d85SBram Moolenaarif &filetype == 'changelog' 32*57657d85SBram Moolenaar if exists('b:did_ftplugin') 33071d4279SBram Moolenaar finish 34071d4279SBram Moolenaar endif 35071d4279SBram Moolenaar let b:did_ftplugin = 1 36071d4279SBram Moolenaar 3742eeac35SBram Moolenaar let s:cpo_save = &cpo 3842eeac35SBram Moolenaar set cpo&vim 39071d4279SBram Moolenaar 40*57657d85SBram Moolenaar " Set up the format used for dates. 41*57657d85SBram Moolenaar if !exists('g:changelog_dateformat') 42*57657d85SBram Moolenaar if exists('g:changelog_timeformat') 43*57657d85SBram Moolenaar let g:changelog_dateformat = g:changelog_timeformat 44*57657d85SBram Moolenaar else 45*57657d85SBram Moolenaar let g:changelog_dateformat = "%Y-%m-%d" 46*57657d85SBram Moolenaar endif 47071d4279SBram Moolenaar endif 48071d4279SBram Moolenaar 49071d4279SBram Moolenaar " Try to figure out a reasonable username of the form: 50*57657d85SBram Moolenaar " Full Name <user@host>. 51*57657d85SBram Moolenaar if !exists('g:changelog_username') 52*57657d85SBram Moolenaar if exists('$EMAIL') && $EMAIL != '' 53071d4279SBram Moolenaar let g:changelog_username = $EMAIL 54*57657d85SBram Moolenaar elseif exists('$EMAIL_ADDRESS') && $EMAIL_ADDRESS != '' 55*57657d85SBram Moolenaar " This is some Debian junk if I remember correctly. 56*57657d85SBram Moolenaar let g:changelog_username = $EMAIL_ADDRESS 57071d4279SBram Moolenaar else 58*57657d85SBram Moolenaar " Get the users login name. 59071d4279SBram Moolenaar let login = system('whoami') 60071d4279SBram Moolenaar if v:shell_error 61071d4279SBram Moolenaar let login = 'unknown' 62071d4279SBram Moolenaar else 63071d4279SBram Moolenaar let newline = stridx(login, "\n") 64071d4279SBram Moolenaar if newline != -1 65071d4279SBram Moolenaar let login = strpart(login, 0, newline) 66071d4279SBram Moolenaar endif 67071d4279SBram Moolenaar endif 68071d4279SBram Moolenaar 69*57657d85SBram Moolenaar " Try to get the full name from gecos field in /etc/passwd. 70071d4279SBram Moolenaar if filereadable('/etc/passwd') 71*57657d85SBram Moolenaar for line in readfile('/etc/passwd') 72*57657d85SBram Moolenaar if line =~ '^' . login 73*57657d85SBram Moolenaar let name = substitute(line,'^\%([^:]*:\)\{4}\([^:]*\):.*$','\1','') 74*57657d85SBram Moolenaar " Only keep stuff before the first comma. 75071d4279SBram Moolenaar let comma = stridx(name, ',') 76071d4279SBram Moolenaar if comma != -1 77071d4279SBram Moolenaar let name = strpart(name, 0, comma) 78071d4279SBram Moolenaar endif 79*57657d85SBram Moolenaar " And substitute & in the real name with the login of our user. 80071d4279SBram Moolenaar let amp = stridx(name, '&') 81071d4279SBram Moolenaar if amp != -1 82071d4279SBram Moolenaar let name = strpart(name, 0, amp) . toupper(login[0]) . 83071d4279SBram Moolenaar \ strpart(login, 1) . strpart(name, amp + 1) 84071d4279SBram Moolenaar endif 85*57657d85SBram Moolenaar endif 86*57657d85SBram Moolenaar endfor 87*57657d85SBram Moolenaar endif 88071d4279SBram Moolenaar 89*57657d85SBram Moolenaar " If we haven't found a name, try to gather it from other places. 90*57657d85SBram Moolenaar if !exists('name') 91*57657d85SBram Moolenaar " Maybe the environment has something of interest. 92*57657d85SBram Moolenaar if exists("$NAME") 93*57657d85SBram Moolenaar let name = $NAME 94*57657d85SBram Moolenaar else 95*57657d85SBram Moolenaar " No? well, use the login name and capitalize first 96*57657d85SBram Moolenaar " character. 97*57657d85SBram Moolenaar let name = toupper(login[0]) . strpart(login, 1) 98*57657d85SBram Moolenaar endif 99*57657d85SBram Moolenaar endif 100*57657d85SBram Moolenaar 101*57657d85SBram Moolenaar " Get our hostname. 102*57657d85SBram Moolenaar let hostname = system('hostname') 103071d4279SBram Moolenaar if v:shell_error 104*57657d85SBram Moolenaar let hostname = 'localhost' 105071d4279SBram Moolenaar else 106071d4279SBram Moolenaar let newline = stridx(hostname, "\n") 107071d4279SBram Moolenaar if newline != -1 108071d4279SBram Moolenaar let hostname = strpart(hostname, 0, newline) 109071d4279SBram Moolenaar endif 110071d4279SBram Moolenaar endif 111071d4279SBram Moolenaar 112*57657d85SBram Moolenaar " And finally set the username. 113071d4279SBram Moolenaar let g:changelog_username = name . ' <' . login . '@' . hostname . '>' 114071d4279SBram Moolenaar endif 115071d4279SBram Moolenaar endif 116071d4279SBram Moolenaar 117*57657d85SBram Moolenaar " Format used for new date entries. 118*57657d85SBram Moolenaar if !exists('g:changelog_new_date_format') 119071d4279SBram Moolenaar let g:changelog_new_date_format = "%d %u\n\n\t* %c\n\n" 120071d4279SBram Moolenaar endif 121071d4279SBram Moolenaar 122*57657d85SBram Moolenaar " Format used for new entries to current date entry. 123*57657d85SBram Moolenaar if !exists('g:changelog_new_entry_format') 124071d4279SBram Moolenaar let g:changelog_new_entry_format = "\t* %c" 125071d4279SBram Moolenaar endif 126071d4279SBram Moolenaar 127*57657d85SBram Moolenaar " Regular expression used to find a given date entry. 128*57657d85SBram Moolenaar if !exists('g:changelog_date_entry_search') 129071d4279SBram Moolenaar let g:changelog_date_entry_search = '^\s*%d\_s*%u' 130071d4279SBram Moolenaar endif 131071d4279SBram Moolenaar 132*57657d85SBram Moolenaar " Substitutes specific items in new date-entry formats and search strings. 133*57657d85SBram Moolenaar " Can be done with substitute of course, but unclean, and need \@! then. 134071d4279SBram Moolenaar function! s:substitute_items(str, date, user) 135071d4279SBram Moolenaar let str = a:str 136*57657d85SBram Moolenaar let middles = {'%': '%', 'd': a:date, 'u': a:user, 'c': '{cursor}'} 137071d4279SBram Moolenaar let i = stridx(str, '%') 138071d4279SBram Moolenaar while i != -1 139*57657d85SBram Moolenaar let inc = 0 140*57657d85SBram Moolenaar if has_key(middles, str[i + 1]) 141*57657d85SBram Moolenaar let mid = middles[str[i + 1]] 142*57657d85SBram Moolenaar let str = strpart(str, 0, i) . mid . strpart(str, i + 2) 143*57657d85SBram Moolenaar let inc = strlen(mid) 144071d4279SBram Moolenaar endif 145*57657d85SBram Moolenaar let i = stridx(str, '%', i + 1 + inc) 146071d4279SBram Moolenaar endwhile 147071d4279SBram Moolenaar return str 148071d4279SBram Moolenaar endfunction 149071d4279SBram Moolenaar 150*57657d85SBram Moolenaar " Position the cursor once we've done all the funky substitution. 151071d4279SBram Moolenaar function! s:position_cursor() 152071d4279SBram Moolenaar if search('{cursor}') > 0 153*57657d85SBram Moolenaar let lnum = line('.') 154*57657d85SBram Moolenaar let line = getline(lnum) 155071d4279SBram Moolenaar let cursor = stridx(line, '{cursor}') 156*57657d85SBram Moolenaar call setline(lnum, substitute(line, '{cursor}', '', '')) 157071d4279SBram Moolenaar endif 158071d4279SBram Moolenaar startinsert! 159071d4279SBram Moolenaar endfunction 160071d4279SBram Moolenaar 161*57657d85SBram Moolenaar " Internal function to create a new entry in the ChangeLog. 162071d4279SBram Moolenaar function! s:new_changelog_entry() 163*57657d85SBram Moolenaar " Deal with 'paste' option. 164071d4279SBram Moolenaar let save_paste = &paste 165071d4279SBram Moolenaar let &paste = 1 166*57657d85SBram Moolenaar call cursor(1, 1) 167*57657d85SBram Moolenaar " Look for an entry for today by our user. 168*57657d85SBram Moolenaar let date = strftime(g:changelog_dateformat) 169071d4279SBram Moolenaar let search = s:substitute_items(g:changelog_date_entry_search, date, 170071d4279SBram Moolenaar \ g:changelog_username) 171071d4279SBram Moolenaar if search(search) > 0 172*57657d85SBram Moolenaar " Ok, now we look for the end of the date entry, and add an entry. 173*57657d85SBram Moolenaar call cursor(nextnonblank(line('.') + 1), 1) 174*57657d85SBram Moolenaar if search('^\s*$', 'W') > 0 175*57657d85SBram Moolenaar let p = line('.') - 1 176071d4279SBram Moolenaar else 177*57657d85SBram Moolenaar let p = line('.') 178*57657d85SBram Moolenaar endif 179*57657d85SBram Moolenaar let ls = split(s:substitute_items(g:changelog_new_entry_format, '', ''), 180*57657d85SBram Moolenaar \ '\n') 181*57657d85SBram Moolenaar call append(p, ls) 182*57657d85SBram Moolenaar call cursor(p + 1, 1) 183*57657d85SBram Moolenaar else 184*57657d85SBram Moolenaar " Flag for removing empty lines at end of new ChangeLogs. 185071d4279SBram Moolenaar let remove_empty = line('$') == 1 186071d4279SBram Moolenaar 187*57657d85SBram Moolenaar " No entry today, so create a date-user header and insert an entry. 188071d4279SBram Moolenaar let todays_entry = s:substitute_items(g:changelog_new_date_format, 189071d4279SBram Moolenaar \ date, g:changelog_username) 190*57657d85SBram Moolenaar " Make sure we have a cursor positioning. 191071d4279SBram Moolenaar if stridx(todays_entry, '{cursor}') == -1 192071d4279SBram Moolenaar let todays_entry = todays_entry . '{cursor}' 193071d4279SBram Moolenaar endif 194071d4279SBram Moolenaar 195*57657d85SBram Moolenaar " Now do the work. 196*57657d85SBram Moolenaar call append(0, split(todays_entry, '\n')) 197*57657d85SBram Moolenaar 198*57657d85SBram Moolenaar " Remove empty lines at end of file. 199071d4279SBram Moolenaar if remove_empty 200*57657d85SBram Moolenaar $-/^\s*$/-1,$delete 201071d4279SBram Moolenaar endif 202071d4279SBram Moolenaar 203*57657d85SBram Moolenaar " Reposition cursor once we're done. 204*57657d85SBram Moolenaar call cursor(1, 1) 205071d4279SBram Moolenaar endif 206071d4279SBram Moolenaar 207071d4279SBram Moolenaar call s:position_cursor() 208071d4279SBram Moolenaar 209071d4279SBram Moolenaar " And reset 'paste' option 210071d4279SBram Moolenaar let &paste = save_paste 211071d4279SBram Moolenaar endfunction 212071d4279SBram Moolenaar 213071d4279SBram Moolenaar if exists(":NewChangelogEntry") != 2 214071d4279SBram Moolenaar map <buffer> <silent> <Leader>o <Esc>:call <SID>new_changelog_entry()<CR> 215071d4279SBram Moolenaar command! -nargs=0 NewChangelogEntry call s:new_changelog_entry() 216071d4279SBram Moolenaar endif 217071d4279SBram Moolenaar 218*57657d85SBram Moolenaar let b:undo_ftplugin = "setl com< fo< et< ai<" 219071d4279SBram Moolenaar 220071d4279SBram Moolenaar setlocal comments= 221071d4279SBram Moolenaar setlocal formatoptions+=t 222071d4279SBram Moolenaar setlocal noexpandtab 22342eeac35SBram Moolenaar setlocal autoindent 224071d4279SBram Moolenaar 225*57657d85SBram Moolenaar if &textwidth == 0 226*57657d85SBram Moolenaar setlocal textwidth=78 227*57657d85SBram Moolenaar let b:undo_ftplugin .= " tw<" 228*57657d85SBram Moolenaar endif 229*57657d85SBram Moolenaar 23042eeac35SBram Moolenaar let &cpo = s:cpo_save 23142eeac35SBram Moolenaar unlet s:cpo_save 232071d4279SBram Moolenaarelse 233071d4279SBram Moolenaar " Add the Changelog opening mapping 234071d4279SBram Moolenaar nmap <silent> <Leader>o :call <SID>open_changelog()<CR> 235071d4279SBram Moolenaar 236071d4279SBram Moolenaar function! s:open_changelog() 237*57657d85SBram Moolenaar if !filereadable('ChangeLog') 238*57657d85SBram Moolenaar return 239*57657d85SBram Moolenaar endif 240071d4279SBram Moolenaar let buf = bufnr('ChangeLog') 241*57657d85SBram Moolenaar if buf != -1 242*57657d85SBram Moolenaar if bufwinnr(buf) != -1 243*57657d85SBram Moolenaar execute buf . 'wincmd w' 244*57657d85SBram Moolenaar else 245*57657d85SBram Moolenaar execute 'bsplit' buf 246*57657d85SBram Moolenaar endif 247071d4279SBram Moolenaar else 248071d4279SBram Moolenaar split ChangeLog 249071d4279SBram Moolenaar endif 250071d4279SBram Moolenaar 251*57657d85SBram Moolenaar call s:new_changelog_entry() 252071d4279SBram Moolenaar endfunction 253071d4279SBram Moolenaarendif 254