home *** CD-ROM | disk | FTP | other *** search
/ vim.ftp.fu-berlin.de / 2015-02-03.vim.ftp.fu-berlin.de.tar / vim.ftp.fu-berlin.de / runtime / dos / ftplugin / changelog.vim < prev    next >
Encoding:
Text File  |  2011-05-27  |  8.8 KB  |  303 lines

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