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