This guide will help you create a new WakaTime plugin for your text editor/IDE.
Please let us know if you're building a WakaTime plugin! We can help you through Slack or email!
We can also evangelize and help promote your new plugin to all WakaTime users.
A WakaTime plugin is simple… just run the wakatime-cli command and pass it the current file as an argument.
$ pip install wakatime
$ wakatime --file myfile.txt
The code above sends a heartbeat to the WakaTime API and starts logging time.
--apikey XXXX
.
WakaTime plugins have two parts:
Source code for existing plugins can be viewed on the WakaTime GitHub profile.
This is a high-level overview of a WakaTime plugin from the time it's loaded, until the editor is exited.
Send heartbeat
function with isWrite falseSend heartbeat
function with isWrite falseSend heartbeat
function with isWrite trueSend heartbeat
function
lastHeartbeat
variable. if isWrite is false, and file has not changed since last heartbeat, and less than 2 minutes since last heartbeat, then return and do nothinglastHeartbeat
variable with current file and current timeThis happens every time your plugin is loaded, for example when the user opens their text editor/IDE or when the user first installs the plugin.
Examples of init code can be viewed here:
wakatime-cli is a Python module containing common code that every plugin uses. It does things like detect the current project, current branch, syntax language, and send heartbeats to the WakaTime api. To send a heartbeat, your plugin should run wakatime-cli in a background process and pass it the absolute path of the current file.
Some plugins are able to include wakatime-cli along with the plugin code, or using a build script.
If your text editor/IDE can not include resource files in plugin distributions, in the plugin's init function check that the wakatime/cli.py
file exists in the plugin's local directory.
If the wakatime/cli.py
file is not found, download wakatime-cli from the GitHub zip archive, then unzip it into the plugin's local directory.
Examples of downloading and unzipping wakatime-cli can be found here:
Since wakatime-cli is a Python module, in your plugin's init function you should make sure Python is installed on the user's machine. If python isn't found (usually only on Windows machines) then your plugin should download and install Python.
Examples of detecting Python are here:
Examples of downloading and installing Python can be viewed here:
The last step when initializing your plugin is setting up event listeners. Most editors support some version of these events:
These three events are the only ones we care about. When one of these three events are detected, your plugin should send the file to wakatime-cli
.
Some examples of listening for these events:
Every event handler should call the same function, sometimes passing the currently focused file as a parameter if needed. The only catch is the File Save
event needs to pass a boolean to indicate this heartbeat was triggered from saving to a file.
The file changed event detects when the editor focus has changed to a new file. For example, when the user switches to a new tab in their editor.
The file modified event should be triggered every time the currently focused file is changed. If your editor only supports detecting the first time a file is modified, you should detect when a user presses a key instead.
The file saved event detects when a file's modified contents are written to disk.
Every event handler should call the same function. This common function should accept one argument, the boolean indicating whether this event was triggered from saving to a file(true
) or not(false
).
The first thing this function should do is detect the currently focused file. If there is no way to detect the currently focused file, the event handlers can pass the current file as an argument.
This function should decide whether to send the file to wakatime-cli
or not, depending on how long it has been since it last sent the same file to wakatime-cli
. Here's some example Python showing this decision:
if enoughTimeHasPassed(lastSentTime) or currentlyFocusedFileHasChanged(lastSentFile) or isFileSavedEvent():
sendFileToWakatimeCLI()
else:
# do nothing
pass
The enoughTimeHasPassed
function checks if more than 2 minutes have passed since this function has executed last, to prevent sending the currently focused file to wakatime-cli
too frequently. In this case, it would check if lastSentTime
times 120
seconds is greater than the current time.
The currentlyFocusedFileHasChanged
function checks if the absolute path to the currently focused file equals lastSentFile
and returns True
if it does not equal and False
if it is equal.
The isFileSavedEvent
function checks the boolean passed from the event handlers, and returns it as-is.
Now that we have decided to send the file to wakatime-cli
, we need to execute it as a background process and pass the current file as a command line argument. For reference, here is the wakatime-cli
help:
$ python ./wakatime/cli.py --help
usage: wakatime [-h] [--entity FILE] [--key KEY] [--write] [--plugin PLUGIN]
[--time time] [--lineno LINENO] [--cursorpos CURSORPOS]
[--entity-type ENTITY_TYPE] [--proxy PROXY] [--project PROJECT]
[--alternate-project ALTERNATE_PROJECT] [--hostname HOSTNAME]
[--disableoffline] [--hidefilenames] [--exclude EXCLUDE]
[--include INCLUDE] [--logfile LOGFILE] [--apiurl API_URL]
[--timeout TIMEOUT] [--config CONFIG] [--verbose] [--version]
Common interface for the WakaTime api.
optional arguments:
-h, --help show this help message and exit
--entity FILE absolute path to file for the heartbeat; can also be a
url, domain, or app when --entity-type is not file
--key KEY your wakatime api key; uses api_key from
~/.wakatime.conf by default
--write when set, tells api this heartbeat was triggered from
writing to a file
--plugin PLUGIN optional text editor plugin name and version for User-
Agent header
--time time optional floating-point unix epoch timestamp; uses
current time by default
--lineno LINENO optional line number; current line being edited
--cursorpos CURSORPOS
optional cursor position in the current file
--entity-type ENTITY_TYPE
entity type for this heartbeat. can be one of "file",
"domain", or "app"; defaults to file.
--proxy PROXY optional https proxy url; for example:
https://user:pass@localhost:8080
--project PROJECT optional project name
--alternate-project ALTERNATE_PROJECT
optional alternate project name; auto-discovered
project takes priority
--hostname HOSTNAME hostname of current machine.
--disableoffline disables offline time logging instead of queuing
coding activity
--hidefilenames obfuscate file names; will not send file names to api
--exclude EXCLUDE filename patterns to exclude from logging; POSIX regex
syntax; can be used more than once
--include INCLUDE filename patterns to log; when used in combination
with --exclude, files matching include will still be
logged; POSIX regex syntax; can be used more than once
--logfile LOGFILE defaults to ~/.wakatime.log
--apiurl API_URL heartbeats api url; for debugging with a local server
--timeout TIMEOUT number of seconds to wait when sending heartbeats to
api
--config CONFIG defaults to ~/.wakatime.conf
--verbose turns on debug messages in log file
--version show program's version number and exit
Some examples of executing wakatime-cli
:
After sending the currently focused file to wakatime-cli
, your plugin should update the lastSentTime
and lastSentFile
global variables with the current time and currently focused file. This way they will be ready the next time we are handling an event.
Some resources you can use while debugging your plugin.
To confirm your heartbeats are being received by the WakaTime API, check the current user resource and look for changes to the last_plugin
and last_heartbeat
attributes:
https://wakatime.com/api/v1/users/current
If your plugin is working, you should see the last_plugin
attribute showing your plugin's name and version. You will also see the last_heartbeat
timestamp update every time a heartbeat is received.
Logging errors and info messages from your plugin is a good way to debug problems. Each editor/IDE running your plugin usually provides a log for appending messages. You should setup logging to write there from your plugin and watch it while debugging.
wakatime-cli
has it's own log file located at $HOME/.wakatime.log
. To turn on verbose logging, pass the --verbose
argument to wakatime-cli
. With the --verbose
flag, wakatime-cli
will write DEBUG messages to the $HOME/.wakatime.log
file.
Things to do once your plugin is sending heartbeats.
Keep track of your plugin's version number with Semantic Versioning.
Send your plugin's version number and name to wakatime-cli
with the --plugin
argument.
Put it on GitHub and send us your repository in an email to alan@wakatime.com.
Each editor/IDE does this differently. Some editors come with built-in plugin management, where you submit a new version and it handles updating.