1071d4279SBram Moolenaar" Vim filetype plugin file
2071d4279SBram Moolenaar" Language:         generic Changelog file
3*42eeac35SBram Moolenaar" Maintainer:       Nikolai Weibull <[email protected]>
4*42eeac35SBram Moolenaar" Latest Revision:  2005-06-29
5071d4279SBram Moolenaar" Variables:
6071d4279SBram Moolenaar"   g:changelog_timeformat -
7071d4279SBram Moolenaar"       description: the timeformat used in ChangeLog entries.
8071d4279SBram Moolenaar"       default: "%Y-%m-%d".
9071d4279SBram Moolenaar"   g:changelog_username -
10071d4279SBram Moolenaar"       description: the username to use in ChangeLog entries
11071d4279SBram Moolenaar"       default: try to deduce it from environment variables and system files.
12071d4279SBram Moolenaar" Local Mappings:
13071d4279SBram Moolenaar"   <Leader>o -
14071d4279SBram Moolenaar"       adds a new changelog entry for the current user for the current date.
15071d4279SBram Moolenaar" Global Mappings:
16071d4279SBram Moolenaar"   <Leader>o -
17071d4279SBram Moolenaar"       switches to the ChangeLog buffer opened for the current directory, or
18071d4279SBram Moolenaar"       opens it in a new buffer if it exists in the current directory.  Then
19071d4279SBram Moolenaar"       it does the same as the local <Leader>o described above.
20071d4279SBram Moolenaar" Notes:
21071d4279SBram Moolenaar"   run 'runtime ftplugin/changelog.vim' to enable the global mapping for
22071d4279SBram Moolenaar"   changelog files.
23071d4279SBram Moolenaar" TODO:
24071d4279SBram Moolenaar"  should we perhaps open the ChangeLog file even if it doesn't exist already?
25071d4279SBram Moolenaar"  Problem is that you might end up with ChangeLog files all over the place.
26071d4279SBram Moolenaar
27071d4279SBram Moolenaar" If 'filetype' isn't "changelog", we must have been to add ChangeLog opener
28071d4279SBram Moolenaarif &filetype == "changelog"
29071d4279SBram Moolenaar  if exists("b:did_ftplugin")
30071d4279SBram Moolenaar    finish
31071d4279SBram Moolenaar  endif
32071d4279SBram Moolenaar  let b:did_ftplugin = 1
33071d4279SBram Moolenaar
34*42eeac35SBram Moolenaar  let s:cpo_save = &cpo
35*42eeac35SBram Moolenaar  set cpo&vim
36071d4279SBram Moolenaar
37071d4279SBram Moolenaar  " The format of the date-time field (should have been called dateformat)
38071d4279SBram Moolenaar  if !exists("g:changelog_timeformat")
39071d4279SBram Moolenaar    let g:changelog_timeformat = "%Y-%m-%d"
40071d4279SBram Moolenaar  endif
41071d4279SBram Moolenaar
42071d4279SBram Moolenaar  " Try to figure out a reasonable username of the form:
43071d4279SBram Moolenaar  " Full Name <user@host>
44071d4279SBram Moolenaar  if !exists("g:changelog_username")
45071d4279SBram Moolenaar    if exists("$EMAIL_ADDRESS")
46071d4279SBram Moolenaar      let g:changelog_username = $EMAIL_ADDRESS
47071d4279SBram Moolenaar    elseif exists("$EMAIL")
48071d4279SBram Moolenaar      let g:changelog_username = $EMAIL
49071d4279SBram Moolenaar    else
50071d4279SBram Moolenaar      " Get the users login name
51071d4279SBram Moolenaar      let login = system('whoami')
52071d4279SBram Moolenaar      if v:shell_error
53071d4279SBram Moolenaar        let login = 'unknown'
54071d4279SBram Moolenaar      else
55071d4279SBram Moolenaar        let newline = stridx(login, "\n")
56071d4279SBram Moolenaar        if newline != -1
57071d4279SBram Moolenaar          let login = strpart(login, 0, newline)
58071d4279SBram Moolenaar        endif
59071d4279SBram Moolenaar      endif
60071d4279SBram Moolenaar
61071d4279SBram Moolenaar      " Try to full name from gecos field in /etc/passwd
62071d4279SBram Moolenaar      if filereadable('/etc/passwd')
63071d4279SBram Moolenaar        let name = substitute(
64071d4279SBram Moolenaar              \system('cat /etc/passwd | grep ^`whoami`'),
65071d4279SBram Moolenaar              \'^\%([^:]*:\)\{4}\([^:]*\):.*$', '\1', '')
66071d4279SBram Moolenaar      endif
67071d4279SBram Moolenaar
68071d4279SBram Moolenaar      " If there is no such file, or there was some other problem try
69071d4279SBram Moolenaar      " others
70071d4279SBram Moolenaar      if !filereadable('/etc/passwd') || v:shell_error
71071d4279SBram Moolenaar        " Maybe the environment has something of interest
72071d4279SBram Moolenaar        if exists("$NAME")
73071d4279SBram Moolenaar          let name = $NAME
74071d4279SBram Moolenaar        else
75071d4279SBram Moolenaar          " No? well, use the login name and capitalize first
76071d4279SBram Moolenaar          " character
77071d4279SBram Moolenaar          let name = toupper(login[0]) . strpart(login, 1)
78071d4279SBram Moolenaar        endif
79071d4279SBram Moolenaar      endif
80071d4279SBram Moolenaar
81071d4279SBram Moolenaar      " Only keep stuff before the first comma
82071d4279SBram Moolenaar      let comma = stridx(name, ',')
83071d4279SBram Moolenaar      if comma != -1
84071d4279SBram Moolenaar        let name = strpart(name, 0, comma)
85071d4279SBram Moolenaar      endif
86071d4279SBram Moolenaar
87071d4279SBram Moolenaar      " And substitute & in the real name with the login of our user
88071d4279SBram Moolenaar      let amp = stridx(name, '&')
89071d4279SBram Moolenaar      if amp != -1
90071d4279SBram Moolenaar        let name = strpart(name, 0, amp) . toupper(login[0]) .
91071d4279SBram Moolenaar              \strpart(login, 1) . strpart(name, amp + 1)
92071d4279SBram Moolenaar      endif
93071d4279SBram Moolenaar
94071d4279SBram Moolenaar      " Get our hostname
95071d4279SBram Moolenaar      let hostname = system("hostname")
96071d4279SBram Moolenaar      if v:shell_error
97071d4279SBram Moolenaar        let hostname = 'unknownhost'
98071d4279SBram Moolenaar      else
99071d4279SBram Moolenaar        let newline = stridx(hostname, "\n")
100071d4279SBram Moolenaar        if newline != -1
101071d4279SBram Moolenaar          let hostname = strpart(hostname, 0, newline)
102071d4279SBram Moolenaar        endif
103071d4279SBram Moolenaar      endif
104071d4279SBram Moolenaar
105071d4279SBram Moolenaar      " And finally set the username
106071d4279SBram Moolenaar      let g:changelog_username = name.'  <'.login.'@'.hostname.'>'
107071d4279SBram Moolenaar    endif
108071d4279SBram Moolenaar  endif
109071d4279SBram Moolenaar
110071d4279SBram Moolenaar  " Format used for new date-entries
111071d4279SBram Moolenaar  if !exists("g:changelog_new_date_format")
112071d4279SBram Moolenaar    let g:changelog_new_date_format = "%d  %u\n\n\t* %c\n\n"
113071d4279SBram Moolenaar  endif
114071d4279SBram Moolenaar
115071d4279SBram Moolenaar  " Format used for new entries to current date-entry
116071d4279SBram Moolenaar  if !exists("g:changelog_new_entry_format")
117071d4279SBram Moolenaar    let g:changelog_new_entry_format = "\t* %c"
118071d4279SBram Moolenaar  endif
119071d4279SBram Moolenaar
120071d4279SBram Moolenaar  if !exists("g:changelog_date_entry_search")
121071d4279SBram Moolenaar    let g:changelog_date_entry_search = '^\s*%d\_s*%u'
122071d4279SBram Moolenaar  endif
123071d4279SBram Moolenaar
124071d4279SBram Moolenaar  " Substitutes specific items in new date-entry formats and search strings
125071d4279SBram Moolenaar  " Can be done with substitute of course, but unclean, and need \@! then
126071d4279SBram Moolenaar  function! s:substitute_items(str, date, user)
127071d4279SBram Moolenaar    let str = a:str
128071d4279SBram Moolenaar    let i = stridx(str, '%')
129071d4279SBram Moolenaar    while i != -1
130071d4279SBram Moolenaar      let char = str[i + 1]
131071d4279SBram Moolenaar      if char == '%'
132071d4279SBram Moolenaar        let middle = '%'
133071d4279SBram Moolenaar      elseif char == 'd'
134071d4279SBram Moolenaar        let middle = a:date
135071d4279SBram Moolenaar      elseif char == 'u'
136071d4279SBram Moolenaar        let middle = a:user
137071d4279SBram Moolenaar      elseif char == 'c'
138071d4279SBram Moolenaar        let middle = '{cursor}'
139071d4279SBram Moolenaar      else
140071d4279SBram Moolenaar        let middle = char
141071d4279SBram Moolenaar      endif
142071d4279SBram Moolenaar      let str = strpart(str, 0, i) . middle . strpart(str, i + 2)
143071d4279SBram Moolenaar      let i = stridx(str, '%')
144071d4279SBram Moolenaar    endwhile
145071d4279SBram Moolenaar    return str
146071d4279SBram Moolenaar  endfunction
147071d4279SBram Moolenaar
148071d4279SBram Moolenaar  function! s:position_cursor()
149071d4279SBram Moolenaar    if search('{cursor}') > 0
150071d4279SBram Moolenaar      let pos = line('.')
151071d4279SBram Moolenaar      let line = getline(pos)
152071d4279SBram Moolenaar      let cursor = stridx(line, '{cursor}')
153071d4279SBram Moolenaar      call setline(pos, substitute(line, '{cursor}', '', ''))
154071d4279SBram Moolenaar    endif
155071d4279SBram Moolenaar    startinsert!
156071d4279SBram Moolenaar  endfunction
157071d4279SBram Moolenaar
158071d4279SBram Moolenaar  " Internal function to create a new entry in the ChangeLog
159071d4279SBram Moolenaar  function! s:new_changelog_entry()
160071d4279SBram Moolenaar    " Deal with 'paste' option
161071d4279SBram Moolenaar    let save_paste = &paste
162071d4279SBram Moolenaar    let &paste = 1
163071d4279SBram Moolenaar    1
164071d4279SBram Moolenaar    " Look for an entry for today by our user
165071d4279SBram Moolenaar    let date = strftime(g:changelog_timeformat)
166071d4279SBram Moolenaar    let search = s:substitute_items(g:changelog_date_entry_search, date,
167071d4279SBram Moolenaar          \g:changelog_username)
168071d4279SBram Moolenaar    if search(search) > 0
169071d4279SBram Moolenaar      " Ok, now we look for the end of the date-entry, and add an entry
170071d4279SBram Moolenaar      let pos = nextnonblank(line('.') + 1)
171071d4279SBram Moolenaar      let line = getline(pos)
172071d4279SBram Moolenaar      while line =~ '^\s\+\S\+'
173071d4279SBram Moolenaar        let pos = pos + 1
174071d4279SBram Moolenaar        let line = getline(pos)
175071d4279SBram Moolenaar      endwhile
176071d4279SBram Moolenaar      let insert = s:substitute_items(g:changelog_new_entry_format,
177071d4279SBram Moolenaar            \'', '')
178071d4279SBram Moolenaar      execute "normal! ".(pos - 1)."Go".insert
179071d4279SBram Moolenaar      execute pos
180071d4279SBram Moolenaar    else
181071d4279SBram Moolenaar      " Flag for removing empty lines at end of new ChangeLogs
182071d4279SBram Moolenaar      let remove_empty = line('$') == 1
183071d4279SBram Moolenaar
184071d4279SBram Moolenaar      " No entry today, so create a date-user header and insert an entry
185071d4279SBram Moolenaar      let todays_entry = s:substitute_items(g:changelog_new_date_format,
186071d4279SBram Moolenaar            \date, g:changelog_username)
187071d4279SBram Moolenaar      " Make sure we have a cursor positioning
188071d4279SBram Moolenaar      if stridx(todays_entry, '{cursor}') == -1
189071d4279SBram Moolenaar        let todays_entry = todays_entry.'{cursor}'
190071d4279SBram Moolenaar      endif
191071d4279SBram Moolenaar
192071d4279SBram Moolenaar      " Now do the work
193071d4279SBram Moolenaar      execute "normal! i".todays_entry
194071d4279SBram Moolenaar      if remove_empty
195071d4279SBram Moolenaar        while getline('$') == ''
196071d4279SBram Moolenaar          $delete
197071d4279SBram Moolenaar        endwhile
198071d4279SBram Moolenaar      endif
199071d4279SBram Moolenaar
200071d4279SBram Moolenaar      1
201071d4279SBram Moolenaar    endif
202071d4279SBram Moolenaar
203071d4279SBram Moolenaar    call s:position_cursor()
204071d4279SBram Moolenaar
205071d4279SBram Moolenaar    " And reset 'paste' option
206071d4279SBram Moolenaar    let &paste = save_paste
207071d4279SBram Moolenaar  endfunction
208071d4279SBram Moolenaar
209071d4279SBram Moolenaar  if exists(":NewChangelogEntry") != 2
210071d4279SBram Moolenaar    map <buffer> <silent> <Leader>o <Esc>:call <SID>new_changelog_entry()<CR>
211071d4279SBram Moolenaar    command! -nargs=0 NewChangelogEntry call s:new_changelog_entry()
212071d4279SBram Moolenaar  endif
213071d4279SBram Moolenaar
214*42eeac35SBram Moolenaar  let b:undo_ftplugin = "setl com< tw< fo< et< ai<"
215071d4279SBram Moolenaar
216071d4279SBram Moolenaar  if &textwidth == 0
217071d4279SBram Moolenaar    setlocal textwidth=78
218071d4279SBram Moolenaar  endif
219071d4279SBram Moolenaar  setlocal comments=
220071d4279SBram Moolenaar  setlocal formatoptions+=t
221071d4279SBram Moolenaar  setlocal noexpandtab
222*42eeac35SBram Moolenaar  setlocal autoindent
223071d4279SBram Moolenaar
224*42eeac35SBram Moolenaar  let &cpo = s:cpo_save
225*42eeac35SBram Moolenaar  unlet s:cpo_save
226071d4279SBram Moolenaarelse
227071d4279SBram Moolenaar  " Add the Changelog opening mapping
228071d4279SBram Moolenaar  nmap <silent> <Leader>o :call <SID>open_changelog()<CR>
229071d4279SBram Moolenaar
230071d4279SBram Moolenaar  function! s:open_changelog()
231071d4279SBram Moolenaar    if filereadable('ChangeLog')
232071d4279SBram Moolenaar      if bufloaded('ChangeLog')
233071d4279SBram Moolenaar        let buf = bufnr('ChangeLog')
234071d4279SBram Moolenaar        execute "normal! \<C-W>t"
235071d4279SBram Moolenaar        while winbufnr(winnr()) != buf
236071d4279SBram Moolenaar          execute "normal! \<C-W>w"
237071d4279SBram Moolenaar        endwhile
238071d4279SBram Moolenaar      else
239071d4279SBram Moolenaar        split ChangeLog
240071d4279SBram Moolenaar      endif
241071d4279SBram Moolenaar
242071d4279SBram Moolenaar      if exists("g:mapleader")
243071d4279SBram Moolenaar        execute "normal " . g:mapleader . "o"
244071d4279SBram Moolenaar      else
245071d4279SBram Moolenaar        execute "normal \\o"
246071d4279SBram Moolenaar      endif
247071d4279SBram Moolenaar      startinsert!
248071d4279SBram Moolenaar    endif
249071d4279SBram Moolenaar  endfunction
250071d4279SBram Moolenaarendif
251