2013-06-25 07:57:15 +00:00
|
|
|
" ============================================================================
|
|
|
|
" File: wakatime.vim
|
2013-07-02 09:24:04 +00:00
|
|
|
" Description: Automatic time tracking for Vim.
|
2013-06-25 07:57:15 +00:00
|
|
|
" Maintainer: Wakati.Me <support@wakatime.com>
|
|
|
|
" ============================================================================
|
|
|
|
|
2013-07-09 16:55:22 +00:00
|
|
|
let s:VERSION = '0.2.1'
|
|
|
|
|
2013-06-26 04:09:52 +00:00
|
|
|
|
2013-06-25 07:57:15 +00:00
|
|
|
" Init {{{
|
|
|
|
|
2013-07-02 09:24:04 +00:00
|
|
|
" Check Vim version
|
|
|
|
if v:version < 700
|
|
|
|
echoerr "This plugin requires vim >= 7."
|
|
|
|
finish
|
2013-06-25 07:57:15 +00:00
|
|
|
endif
|
2013-07-02 09:24:04 +00:00
|
|
|
|
|
|
|
" Check for Python support
|
|
|
|
if !has('python')
|
|
|
|
echoerr "This plugin requires Vim to be compiled with Python support."
|
2013-06-25 07:57:15 +00:00
|
|
|
finish
|
|
|
|
endif
|
|
|
|
|
2013-07-02 09:24:04 +00:00
|
|
|
" Only load plugin once
|
|
|
|
if exists("g:loaded_wakatime")
|
|
|
|
finish
|
|
|
|
endif
|
|
|
|
let g:loaded_wakatime = 1
|
2013-06-25 07:57:15 +00:00
|
|
|
|
2013-07-02 09:24:04 +00:00
|
|
|
" Backup & Override cpoptions
|
|
|
|
let s:old_cpo = &cpo
|
|
|
|
set cpo&vim
|
2013-06-25 07:57:15 +00:00
|
|
|
|
2013-07-08 04:25:06 +00:00
|
|
|
" Set default away minutes
|
|
|
|
if !exists("g:wakatime_AwayMinutes")
|
2013-07-10 04:13:45 +00:00
|
|
|
let g:wakatime_AwayMinutes = 10
|
2013-07-02 09:24:04 +00:00
|
|
|
endif
|
2013-07-09 00:09:43 +00:00
|
|
|
|
2013-07-10 04:13:45 +00:00
|
|
|
" Set default action frequency in minutes
|
2013-07-09 00:09:43 +00:00
|
|
|
if !exists("g:wakatime_ActionFrequency")
|
2013-07-10 04:13:45 +00:00
|
|
|
let g:wakatime_ActionFrequency = 5
|
2013-07-09 00:09:43 +00:00
|
|
|
endif
|
|
|
|
|
|
|
|
" To be backwards compatible, rename config file
|
|
|
|
if filereadable(expand("$HOME/.wakatime"))
|
|
|
|
exec "silent !mv" expand("$HOME/.wakatime") expand("$HOME/.wakatime.conf")
|
|
|
|
endif
|
2013-06-26 05:02:59 +00:00
|
|
|
|
2013-07-08 04:25:06 +00:00
|
|
|
" Globals
|
|
|
|
let s:plugin_directory = expand("<sfile>:p:h") . '/'
|
|
|
|
let s:last_action = 0
|
2013-07-08 05:18:47 +00:00
|
|
|
let s:fresh = 1
|
2013-07-02 04:07:38 +00:00
|
|
|
|
2013-07-08 04:25:06 +00:00
|
|
|
" Import things python needs
|
2013-07-02 09:24:04 +00:00
|
|
|
python import time
|
|
|
|
python import vim
|
2013-06-25 07:57:15 +00:00
|
|
|
|
|
|
|
" }}}
|
|
|
|
|
2013-06-26 04:09:52 +00:00
|
|
|
|
2013-06-25 07:57:15 +00:00
|
|
|
" Function Definitions {{{
|
|
|
|
|
2013-07-02 09:24:04 +00:00
|
|
|
function! s:GetCurrentFile()
|
|
|
|
return expand("%:p")
|
|
|
|
endfunction
|
|
|
|
|
|
|
|
function! s:GetCurrentTime()
|
2013-07-09 00:09:43 +00:00
|
|
|
python vim.command('let current_time=%f' % time.time())
|
2013-07-02 09:24:04 +00:00
|
|
|
return current_time
|
|
|
|
endfunction
|
|
|
|
|
2013-07-08 05:18:47 +00:00
|
|
|
function! s:Api(targetFile, time, endtime, is_write, last)
|
2013-07-08 04:25:06 +00:00
|
|
|
let targetFile = a:targetFile
|
|
|
|
if targetFile == ''
|
2013-07-10 04:13:45 +00:00
|
|
|
let targetFile = a:last[2]
|
2013-07-08 04:25:06 +00:00
|
|
|
endif
|
|
|
|
if targetFile != ''
|
2013-07-09 16:55:22 +00:00
|
|
|
let cmd = ['python', s:plugin_directory . 'packages/wakatime/wakatime.py']
|
|
|
|
let cmd = cmd + ['--file', shellescape(targetFile)]
|
|
|
|
let cmd = cmd + ['--time', printf('%f', a:time)]
|
|
|
|
let cmd = cmd + ['--plugin', printf('vim-wakatime/%s', s:VERSION)]
|
2013-07-08 04:25:06 +00:00
|
|
|
if a:is_write
|
2013-07-09 16:55:22 +00:00
|
|
|
let cmd = cmd + ['--write']
|
2013-07-08 04:25:06 +00:00
|
|
|
endif
|
2013-07-09 16:55:22 +00:00
|
|
|
if a:endtime > 1
|
|
|
|
let cmd = cmd + ['--endtime', printf('%f', a:endtime)]
|
2013-07-08 04:25:06 +00:00
|
|
|
endif
|
2013-07-09 22:34:03 +00:00
|
|
|
"let cmd = cmd + ['--verbose']
|
2013-07-09 16:55:22 +00:00
|
|
|
exec 'silent !' . join(cmd, ' ') . ' &'
|
2013-07-08 04:25:06 +00:00
|
|
|
let time = a:time
|
2013-07-09 16:55:22 +00:00
|
|
|
if a:endtime > 1 && float2nr(round(time)) < float2nr(round(a:endtime))
|
2013-07-08 04:25:06 +00:00
|
|
|
let time = a:endtime
|
|
|
|
endif
|
2013-07-10 07:55:42 +00:00
|
|
|
call s:SetLastAction(time, time, targetFile)
|
2013-07-08 04:25:06 +00:00
|
|
|
endif
|
|
|
|
endfunction
|
|
|
|
|
|
|
|
function! s:GetLastAction()
|
|
|
|
if !filereadable(expand("$HOME/.wakatime.data"))
|
2013-07-10 04:13:45 +00:00
|
|
|
return [0.0, '', 0.0]
|
2013-07-08 04:25:06 +00:00
|
|
|
endif
|
|
|
|
let last = readfile(expand("$HOME/.wakatime.data"), '', 2)
|
2013-07-10 04:13:45 +00:00
|
|
|
if len(last) < 3
|
|
|
|
return [0.0, '', 0.0]
|
2013-07-02 09:24:04 +00:00
|
|
|
endif
|
2013-07-10 04:13:45 +00:00
|
|
|
return [str2float(last[0]), str2float(last[1]), last[2]]
|
2013-07-08 04:25:06 +00:00
|
|
|
endfunction
|
|
|
|
|
2013-07-10 07:55:42 +00:00
|
|
|
function! s:SetLastAction(time, last_update, targetFile)
|
2013-07-08 05:18:47 +00:00
|
|
|
let s:fresh = 0
|
2013-07-10 07:55:42 +00:00
|
|
|
call writefile([printf('%f', a:time), printf('%f', a:last_update), a:targetFile], expand("$HOME/.wakatime.data"))
|
2013-07-02 09:24:04 +00:00
|
|
|
endfunction
|
|
|
|
|
2013-07-08 05:18:47 +00:00
|
|
|
function! s:GetChar()
|
2013-07-02 09:24:04 +00:00
|
|
|
let c = getchar()
|
|
|
|
if c =~ '^\d\+$'
|
|
|
|
let c = nr2char(c)
|
|
|
|
endif
|
|
|
|
return c
|
|
|
|
endfunction
|
2013-07-10 04:13:45 +00:00
|
|
|
|
|
|
|
function! s:EnoughTimePassed(now, last)
|
|
|
|
let prev = a:last[0]
|
|
|
|
if a:now - prev > g:wakatime_ActionFrequency * 60
|
2013-07-08 04:25:06 +00:00
|
|
|
return 1
|
|
|
|
endif
|
|
|
|
return 0
|
2013-07-02 09:24:04 +00:00
|
|
|
endfunction
|
2013-07-08 04:25:06 +00:00
|
|
|
|
2013-07-10 04:13:45 +00:00
|
|
|
function! s:ShouldPromptUser(now, last)
|
|
|
|
let prev = a:last[1]
|
2013-07-10 06:49:04 +00:00
|
|
|
if s:fresh || prev < 1
|
2013-07-08 04:25:06 +00:00
|
|
|
return 0
|
|
|
|
endif
|
2013-07-10 04:13:45 +00:00
|
|
|
let duration = a:now - prev
|
2013-07-08 04:25:06 +00:00
|
|
|
if duration > g:wakatime_AwayMinutes * 60
|
2013-07-10 04:13:45 +00:00
|
|
|
return 1
|
|
|
|
endif
|
|
|
|
return 0
|
|
|
|
endfunction
|
|
|
|
|
2013-07-10 07:05:24 +00:00
|
|
|
function! s:Away(now, last)
|
|
|
|
let duration = a:now - a:last[1]
|
2013-07-10 04:13:45 +00:00
|
|
|
let units = 'seconds'
|
|
|
|
if duration > 59
|
|
|
|
let duration = round(duration / 60)
|
|
|
|
let units = 'minutes'
|
|
|
|
endif
|
|
|
|
if duration > 59
|
|
|
|
let duration = round(duration / 60)
|
|
|
|
let units = 'hours'
|
|
|
|
endif
|
|
|
|
if duration > 24
|
|
|
|
let duration = round(duration / 24)
|
|
|
|
let units = 'days'
|
2013-07-02 09:24:04 +00:00
|
|
|
endif
|
2013-07-10 04:13:45 +00:00
|
|
|
let answer = input(printf("You were away %.f %s. Add time to current file? (y/n)", duration, units))
|
|
|
|
if answer != "y"
|
|
|
|
return 1
|
|
|
|
endif
|
|
|
|
return 0
|
2013-07-02 09:24:04 +00:00
|
|
|
endfunction
|
2013-06-25 07:57:15 +00:00
|
|
|
|
|
|
|
" }}}
|
|
|
|
|
2013-06-26 04:09:52 +00:00
|
|
|
|
2013-06-25 07:57:15 +00:00
|
|
|
" Event Handlers {{{
|
|
|
|
|
2013-07-08 04:25:06 +00:00
|
|
|
function! s:normalAction()
|
|
|
|
let targetFile = s:GetCurrentFile()
|
|
|
|
let now = s:GetCurrentTime()
|
|
|
|
let last = s:GetLastAction()
|
2013-07-10 04:13:45 +00:00
|
|
|
if s:EnoughTimePassed(now, last) || targetFile != last[2]
|
|
|
|
if s:ShouldPromptUser(now, last)
|
|
|
|
if s:Away(now, last)
|
|
|
|
call s:Api(targetFile, now, last[0], 0, last)
|
|
|
|
else
|
|
|
|
call s:Api(targetFile, now, 0.0, 0, last)
|
|
|
|
endif
|
2013-07-08 04:25:06 +00:00
|
|
|
else
|
2013-07-10 04:13:45 +00:00
|
|
|
call s:Api(targetFile, now, last[0], 0, last)
|
2013-07-08 04:25:06 +00:00
|
|
|
endif
|
2013-07-10 04:13:45 +00:00
|
|
|
else
|
2013-07-10 07:55:42 +00:00
|
|
|
if now - last[1] > 5
|
|
|
|
call s:SetLastAction(last[0], now, targetFile)
|
2013-07-10 07:21:47 +00:00
|
|
|
endif
|
2013-07-02 09:24:04 +00:00
|
|
|
endif
|
2013-07-08 04:25:06 +00:00
|
|
|
endfunction
|
2013-07-02 09:24:04 +00:00
|
|
|
|
2013-07-08 04:25:06 +00:00
|
|
|
function! s:writeAction()
|
2013-07-10 04:13:45 +00:00
|
|
|
let targetFile = s:GetCurrentFile()
|
|
|
|
let now = s:GetCurrentTime()
|
|
|
|
let last = s:GetLastAction()
|
|
|
|
if s:EnoughTimePassed(now, last) || targetFile != last[2]
|
|
|
|
if s:ShouldPromptUser(now, last)
|
|
|
|
if s:Away(now, last)
|
|
|
|
call s:Api(targetFile, now, last[0], 1, last)
|
|
|
|
else
|
|
|
|
call s:Api(targetFile, now, 0.0, 1, last)
|
|
|
|
endif
|
|
|
|
else
|
|
|
|
call s:Api(targetFile, now, last[0], 1, last)
|
|
|
|
endif
|
|
|
|
else
|
2013-07-10 06:28:15 +00:00
|
|
|
call s:Api(targetFile, now, 0.0, 1, last)
|
2013-07-10 04:13:45 +00:00
|
|
|
endif
|
2013-07-02 09:24:04 +00:00
|
|
|
endfunction
|
2013-06-25 07:57:15 +00:00
|
|
|
|
|
|
|
" }}}
|
|
|
|
|
2013-06-26 04:09:52 +00:00
|
|
|
|
2013-06-25 07:57:15 +00:00
|
|
|
" Autocommand Events {{{
|
|
|
|
|
2013-07-02 09:24:04 +00:00
|
|
|
augroup Wakatime
|
|
|
|
autocmd!
|
2013-07-08 04:25:06 +00:00
|
|
|
autocmd BufEnter * call s:normalAction()
|
|
|
|
autocmd VimEnter * call s:normalAction()
|
|
|
|
autocmd BufWritePost * call s:writeAction()
|
|
|
|
autocmd CursorMoved,CursorMovedI * call s:normalAction()
|
2013-07-02 09:24:04 +00:00
|
|
|
augroup END
|
2013-06-25 07:57:15 +00:00
|
|
|
|
|
|
|
" }}}
|
|
|
|
|
2013-06-26 04:09:52 +00:00
|
|
|
|
2013-06-25 07:57:15 +00:00
|
|
|
" Restore cpoptions
|
|
|
|
let &cpo = s:old_cpo
|