diff --git a/README.md b/README.md index 34966b4..893a0ba 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ vim-wakatime 0.1.2 =========== -Automatic time tracking. +Automatic time tracking for Vim. Installation ------------ @@ -12,7 +12,7 @@ https://wakati.me 2) Run this shell command replacing KEY with your api key: - echo "api_key=KEY" > ~/.wakatime + echo "api_key=KEY" >> ~/.wakatime 3) Using [Vundle](https://github.com/gmarik/vundle), the Vim plugin manager: diff --git a/plugin/wakatime.py b/plugin/wakatime.py index 3e74495..20b2689 100644 --- a/plugin/wakatime.py +++ b/plugin/wakatime.py @@ -17,7 +17,7 @@ import logging as log # Config -version = '0.1.2' +version = '0.1.3' user_agent = 'vim-wakatime/%s (%s)' % (version, platform.platform()) @@ -118,14 +118,12 @@ def send_action(key, instance, action, task, timestamp, project, tags): url = 'https://www.wakati.me/api/v1/actions' data = { 'type': action, - 'task': task, - 'time': time.time(), + 'task': os.path.realpath(task), + 'time': timestamp, 'instance_id': instance, 'project': project, 'tags': tags, } - if timestamp: - data['time'] = timestamp request = urllib2.Request(url=url, data=json.dumps(data)) request.add_header('User-Agent', user_agent) request.add_header('Content-Type', 'application/json') @@ -173,10 +171,13 @@ def main(argv): if args.verbose: level = log.DEBUG del args.verbose + if not args.timestamp: + args.timestamp = time.time() log.basicConfig(filename=os.path.expanduser('~/.wakatime.log'), format='%(asctime)s vim-wakatime/'+version+' %(levelname)s %(message)s', datefmt='%Y-%m-%dT%H:%M:%SZ', level=level) - tags = tags_from_path(args.task) - project = project_from_path(args.task) - send_action(project=project, tags=tags, **vars(args)) + if os.path.isfile(os.path.realpath(args.task)): + tags = tags_from_path(args.task) + project = project_from_path(args.task) + send_action(project=project, tags=tags, **vars(args)) return 0 diff --git a/plugin/wakatime.vim b/plugin/wakatime.vim index bbe5050..5592232 100644 --- a/plugin/wakatime.vim +++ b/plugin/wakatime.vim @@ -1,221 +1,204 @@ " ============================================================================ " File: wakatime.vim -" Description: invisible time tracker using Wakati.Me +" Description: Automatic time tracking for Vim. " Maintainer: Wakati.Me -" Version: 0.1.2 +" Version: 0.1.3 " ============================================================================ " Init {{{ -" Check Vim version -if v:version < 700 - echoerr "This plugin requires vim >= 7." - finish -endif - -" Check for Python support -if !has('python') - echoerr "This plugin requires Vim to be compiled with Python support." - finish -endif - -" Check for required user-defined settings -if !exists("g:wakatime_api_key") - if filereadable(expand("$HOME/.wakatime")) - for s:line in readfile(expand("$HOME/.wakatime")) - let s:setting = split(s:line, "=") - if s:setting[0] == "api_key" - let g:wakatime_api_key = s:setting[1] - endif - endfor - endif - if !exists("g:wakatime_api_key") + " Check Vim version + if v:version < 700 + echoerr "This plugin requires vim >= 7." finish endif -endif -" Only load plugin once -if exists("g:loaded_wakatime") - finish -endif -let g:loaded_wakatime = 1 + " Check for Python support + if !has('python') + echoerr "This plugin requires Vim to be compiled with Python support." + finish + endif -" Backup & Override cpoptions -let s:old_cpo = &cpo -set cpo&vim + " Check for required user-defined settings + if !exists("g:wakatime_api_key") + if filereadable(expand("$HOME/.wakatime")) + for s:line in readfile(expand("$HOME/.wakatime")) + let s:setting = split(s:line, "=") + if s:setting[0] == "api_key" + let g:wakatime_api_key = s:setting[1] + endif + endfor + endif + if !exists("g:wakatime_api_key") + finish + endif + endif -let s:plugin_directory = expand(":p:h") + " Only load plugin once + if exists("g:loaded_wakatime") + finish + endif + let g:loaded_wakatime = 1 -" Set default updatetime -if !exists("g:wakatime_updatetime") - let g:wakatime_updatetime = 15 " 15 minutes -endif + " Backup & Override cpoptions + let s:old_cpo = &cpo + set cpo&vim -" We are not away until getting a CursorHold event -let s:away_start = 0 + let s:plugin_directory = expand(":p:h") -" Create logfile if does not exist -exec "silent !touch ~/.wakatime.log" + " Set default updatetime + if !exists("g:wakatime_updatetime") + let g:wakatime_updatetime = 15 " 15 minutes + endif -python << ENDPYTHON -import vim -import uuid -import time + " We are not away until getting a CursorHold event + let s:away_start = 0 -instance_id = str(uuid.uuid4()) -vim.command('let s:instance_id = "%s"' % instance_id) -ENDPYTHON + " Create logfile if does not exist + exec "silent !touch ~/.wakatime.log" + + python import time + python import time + python import uuid + python import vim + python instance_id = str(uuid.uuid4()) + python vim.command('let s:instance_id = "%s"' % instance_id) " }}} " Function Definitions {{{ -function! s:initVariable(var, value) - if !exists(a:var) - exec 'let ' . a:var . ' = ' . "'" . substitute(a:value, "'", "''", "g") . "'" - return 1 - endif - return 0 -endfunction + function! s:setUpdateTime() + if &updatetime < 60 * 1000 * 2 + let &updatetime = g:wakatime_updatetime * 60 * 1000 + endif + endfunction + call s:setUpdateTime() -function! s:setUpdateTime() - if &updatetime < 60 * 1000 * 2 - let &updatetime = g:wakatime_updatetime * 60 * 1000 - endif -endfunction + function! s:GetCurrentFile() + return expand("%:p") + endfunction -call s:setUpdateTime() + function! s:GetCurrentTime() + python vim.command('let current_time="%f"' % time.time()) + return current_time + endfunction -function! s:GetCurrentFile() - return expand("%:p") -endfunction + function! s:api(type, task, time) + if a:task != '' + exec "silent !python " . s:plugin_directory . "/wakatime.py --key" g:wakatime_api_key "--instance" s:instance_id "--action" a:type "--task" shellescape(a:task) "--time" a:time . " &" + endif + endfunction -function! s:api(type, task) - if a:task != '' - exec "silent !python " . s:plugin_directory . "/wakatime.py --key" g:wakatime_api_key "--instance" s:instance_id "--action" a:type "--task" shellescape(a:task) . " &" - endif -endfunction + function! s:getchar() + let c = getchar() + if c =~ '^\d\+$' + let c = nr2char(c) + endif + return c + endfunction -function! s:api_with_time(type, task, time) - if a:task != '' - exec "silent !python " . s:plugin_directory . "/wakatime.py --key" g:wakatime_api_key "--instance" s:instance_id "--action" a:type "--task" shellescape(a:task) "--time" printf("%f", a:time) . " &" - endif -endfunction + function! Wakatime_isAway() + return s:away_start + endfunction -function! s:getchar() - let c = getchar() - if c =~ '^\d\+$' - let c = nr2char(c) - endif - return c -endfunction - -function! Wakatime_isAway() - return s:away_start -endfunction - -function! s:allServersAway() - if has('clientserver') - let servers = split(serverlist()) - for server in servers - if server != v:servername - if !remote_expr(server,'Wakatime_isAway()') - return 0 + function! s:allServersAway() + if has('clientserver') + let servers = split(serverlist()) + for server in servers + if server != v:servername + if !remote_expr(server,'Wakatime_isAway()') + return 0 + endif endif - endif - endfor - endif - return 1 -endfunction + endfor + endif + return 1 + endfunction " }}} " Event Handlers {{{ -function! s:bufenter() - let task = s:GetCurrentFile() - call s:api("open_file", task) -endfunction + function! s:bufenter() + call s:api("open_file", s:GetCurrentFile(), s:GetCurrentTime()) + endfunction -function! s:bufleave() - let task = s:GetCurrentFile() - call s:api("close_file", task) -endfunction + function! s:bufleave() + call s:api("close_file", s:GetCurrentFile(), s:GetCurrentTime()) + endfunction -function! s:vimenter() - let task = s:GetCurrentFile() - call s:api("open_editor", task) -endfunction + function! s:vimenter() + call s:api("open_editor", s:GetCurrentFile(), s:GetCurrentTime()) + endfunction -function! s:vimleave() - let task = s:GetCurrentFile() - call s:api("quit_editor", task) -endfunction + function! s:vimleave() + call s:api("quit_editor", s:GetCurrentFile(), s:GetCurrentTime()) + endfunction -function! s:bufwrite() - let task = s:GetCurrentFile() - call s:api("write_file", task) -endfunction + function! s:bufwrite() + call s:api("write_file", s:GetCurrentFile(), s:GetCurrentTime()) + endfunction -function! s:cursorhold() - let s:away_task = s:GetCurrentFile() - python vim.command("let s:away_start=%f" % (time.time() - (float(vim.eval("&updatetime")) / 1000.0))) - autocmd Wakatime CursorMoved,CursorMovedI * call s:cursormoved() -endfunction + function! s:cursorhold() + let s:away_task = s:GetCurrentFile() + python vim.command("let s:away_start=%f" % (time.time() - (float(vim.eval("&updatetime")) / 1000.0))) + autocmd Wakatime CursorMoved,CursorMovedI * call s:cursormoved() + endfunction -function! s:cursormoved() - autocmd! Wakatime CursorMoved,CursorMovedI * + function! s:cursormoved() + autocmd! Wakatime CursorMoved,CursorMovedI * - " Don't do anything unless all other Vim instances are also away - if !s:allServersAway() + " Don't do anything unless all other Vim instances are also away + if !s:allServersAway() + let s:away_start = 0 + call s:api("ping", s:away_task, s:GetCurrentTime()) + return + endif + + python vim.command("let away_end=%f" % time.time()) + let away_unit = "minutes" + let away_duration = (away_end - s:away_start) / 60 + if away_duration < 2 + call s:setUpdateTime() + return + endif + if away_duration > 59 + let away_duration = away_duration / 60 + let away_unit = "hours" + endif + if away_duration > 59 + let away_duration = away_duration / 60 + let away_unit = "days" + endif + let answer = input(printf("You were away %.f %s. Add time to current file? (y/n)", away_duration, away_unit)) + if answer != "y" + call s:api("minimize_editor", s:away_task, printf("%f", s:away_start)) + call s:api("maximize_editor", s:away_task, printf("%f", away_end)) + else + call s:api("ping", s:away_task, s:GetCurrentTime()) + endif let s:away_start = 0 - call s:api("ping", s:away_task) - return - endif - - python vim.command("let away_end=%f" % time.time()) - let away_unit = "minutes" - let away_duration = (away_end - s:away_start) / 60 - if away_duration < 2 - call s:setUpdateTime() - return - endif - if away_duration > 59 - let away_duration = away_duration / 60 - let away_unit = "hours" - endif - if away_duration > 59 - let away_duration = away_duration / 60 - let away_unit = "days" - endif - let answer = input(printf("You were away %.f %s. Add time to current file? (y/n)", away_duration, away_unit)) - if answer != "y" - call s:api_with_time("minimize_editor", s:away_task, s:away_start) - call s:api_with_time("maximize_editor", s:away_task, away_end) - else - call s:api("ping", s:away_task) - endif - let s:away_start = 0 - "redraw! -endfunction + "redraw! + endfunction " }}} " Autocommand Events {{{ -augroup Wakatime - autocmd! - autocmd BufEnter * call s:bufenter() - autocmd BufLeave * call s:bufleave() - autocmd VimEnter * call s:vimenter() - autocmd VimLeave * call s:vimleave() - autocmd BufWritePost * call s:bufwrite() - autocmd CursorHold,CursorHoldI * call s:cursorhold() -augroup END + augroup Wakatime + autocmd! + autocmd BufEnter * call s:bufenter() + autocmd BufLeave * call s:bufleave() + autocmd VimEnter * call s:vimenter() + autocmd VimLeave * call s:vimleave() + autocmd BufWritePost * call s:bufwrite() + autocmd CursorHold,CursorHoldI * call s:cursorhold() + augroup END " }}}