Setup Β· Configure Β· Contribute
A simple, customizable pomodoro timer plugin for Neovim, written in Lua.
In pomo.nvim, most of the functionality is surfaced through the Notifier
instances you configure. A timer can have any number of notifiers, which are essentially callbacks that fire on every tick of the timer (determined by update_interval
) and each significant event, such as when the timer starts, completes, is stopped, or is hidden. pomo.nvim comes with several notifiers out-of-the-box, but it's also easy to create your own.
- πͺΆ Lightweight and asynchronous
- π» Written in Lua
- βοΈ Easily customizable and extendable
- β±οΈ Run multiple concurrent timers and repeat timers, show/hide, pause/resume
- β Integrate with nvim-notify, lualine, telescope, and more
-
:TimerStart TIMELIMIT [NAME]
to start a new timer.The time limit can be specified in hours, minutes, seconds, or a combination of those, and shouldn't include any spaces. For example:
:TimerStart 25m Work
to start a timer for 25 minutes called "Work".:TimerStart 10s
to start a timer for 10 seconds.:TimerStart 1h30m
to start a timer for an hour and a half.
pomo.nvim will recognize multiple forms of the time units, such as "m", "min", "minute", or "minutes" for minutes.
-
:TimerStop [TIMERID]
to stop a running timer, e.g.:TimerStop 1
. If no ID is given, the latest timer is stopped. -
:TimerRepeat TIMELIMIT REPETITIONS [NAME]
to start a repeat timer, e.g.:TimerRepeat 10s 2
to repeat a 10 second timer twice. -
:TimerHide [TIMERID]
to hide the notifiers of a running timer, if the notifiers support that. If no ID is given, the latest timer's notifiers are hidden. -
:TimerShow [TIMERID]
the opposite of:TimerHide
. -
:TimerPause [TIMERID]
pause a timer. If no ID is given, the latest timer is paused. -
:TimerResume [TIMERID]
the opposite of:TimerPause
. -
:TimerSession [SESSION_NAME]
to start a predefined Pomodoro session.Example session configuration in your setup:
require("pomo").setup({ sessions = { pomodoro = { { name = "Work", duration = "25m" }, { name = "Short Break", duration = "5m" }, { name = "Work", duration = "25m" }, { name = "Short Break", duration = "5m" }, { name = "Work", duration = "25m" }, { name = "Long Break", duration = "15m" }, }, }, })
To start the above session, use:
:TimerSession pomodoro
.
π‘ Tip: You can pass -1
as the TIMERID
to apply the command to all active timers.
To setup pomo.nvim you just need to call require("pomo").setup({ ... })
with the desired options. Here are some examples using different plugin managers. The full set of configuration options are listed below.
Using lazy.nvim
return {
"epwalsh/pomo.nvim",
version = "*", -- Recommended, use latest release instead of latest commit
lazy = true,
cmd = { "TimerStart", "TimerRepeat", "TimerSession" },
dependencies = {
-- Optional, but highly recommended if you want to use the "Default" timer
"rcarriga/nvim-notify",
},
opts = {
-- See below for full list of options π
},
}
Using packer.nvim
use({
"epwalsh/pomo.nvim",
tag = "*", -- Recommended, use latest release instead of latest commit
requires = {
-- Optional, but highly recommended if you want to use the "Default" timer
"rcarriga/nvim-notify",
},
config = function()
require("pomo").setup({
-- See below for full list of options π
})
end,
})
This is a complete list of all of the options that can be passed to require("pomo").setup()
. The values represent reasonable defaults, but please read each option carefully and customize it to your needs:
{
-- How often the notifiers are updated.
update_interval = 1000,
-- Configure the default notifiers to use for each timer.
-- You can also configure different notifiers for timers given specific names, see
-- the 'timers' field below.
notifiers = {
-- The "Default" notifier uses 'vim.notify' and works best when you have 'nvim-notify' installed.
{
name = "Default",
opts = {
-- With 'nvim-notify', when 'sticky = true' you'll have a live timer pop-up
-- continuously displayed. If you only want a pop-up notification when the timer starts
-- and finishes, set this to false.
sticky = true,
-- Configure the display icons:
title_icon = "σ±«",
text_icon = "σ°",
-- Replace the above with these if you don't have a patched font:
-- title_icon = "β³",
-- text_icon = "β±οΈ",
},
},
-- The "System" notifier sends a system notification when the timer is finished.
-- Available on MacOS and Windows natively and on Linux via the `libnotify-bin` package.
{ name = "System" },
-- You can also define custom notifiers by providing an "init" function instead of a name.
-- See "Defining custom notifiers" below for an example π
-- { init = function(timer) ... end }
},
-- Override the notifiers for specific timer names.
timers = {
-- For example, use only the "System" notifier when you create a timer called "Break",
-- e.g. ':TimerStart 2m Break'.
Break = {
{ name = "System" },
},
},
-- You can optionally define custom timer sessions.
sessions = {
-- Example session configuration for a session called "pomodoro".
pomodoro = {
{ name = "Work", duration = "25m" },
{ name = "Short Break", duration = "5m" },
{ name = "Work", duration = "25m" },
{ name = "Short Break", duration = "5m" },
{ name = "Work", duration = "25m" },
{ name = "Long Break", duration = "15m" },
},
},
}
To define your own notifier you need to create a pomo.Notifier
Lua class along with a factory init
function to construct your notifier. Your Notifier
class needs to have the following methods
Notifier.start(self)
- Called when the timer starts.Notifier.tick(self, time_left)
- Called periodically (e.g. every second) while the timer is active. Thetime_left
argument is the number of seconds left on the timer.Notifier.done(self)
- Called when the timer finishes.Notifier.stop(self)
- Called when the timer is stopped before finishing.
You can also provide optionally Notifier.show(self)
and Notifier.hide(self)
methods to respond to :TimerShow
and :TimerHide
.
The factory init
function takes 1 or 2 arguments, the timer
(a pomo.Timer
) and optionally a table of options from the opts
field in the notifier's config.
For example, here's a simple notifier that just uses print
:
local PrintNotifier = {}
PrintNotifier.new = function(timer, opts)
local self = setmetatable({}, { __index = PrintNotifier })
self.timer = timer
self.hidden = false
self.opts = opts -- not used
return self
end
PrintNotifier.start = function(self)
print(string.format("Starting timer #%d, %s, for %ds", self.timer.id, self.timer.name, self.timer.time_limit))
end
PrintNotifier.tick = function(self, time_left)
if not self.hidden then
print(string.format("Timer #%d, %s, %ds remaining...", self.timer.id, self.timer.name, time_left))
end
end
PrintNotifier.done = function(self)
print(string.format("Timer #%d, %s, complete", self.timer.id, self.timer.name))
end
PrintNotifier.stop = function(self) end
PrintNotifier.show = function(self)
self.hidden = false
end
PrintNotifier.hide = function(self)
self.hidden = true
end
And then in the notifiers
field of your pomo.nvim config, you'd add the following entry:
{ init = PrintNotifier.new, opts = {} }
The "Default" notifier integrates seamlessly with nvim-notify
, you just need to have nvim-notify
installed.
pomo.nvim can easily be added to a section in your lualine
. For example, this would extend the defaults for section X to include the next timer to finish (min time remaining):
require("lualine").setup {
sections = {
lualine_x = {
function()
local ok, pomo = pcall(require, "pomo")
if not ok then
return ""
end
local timer = pomo.get_first_to_finish()
if timer == nil then
return ""
end
return "σ° " .. tostring(timer)
end,
"encoding",
"fileformat",
"filetype",
},
},
}
Pomo.nvim ships with a telescope extension for managing timers. Here's an example of mapping the keys <leader>pt
to open the telescope picker for timers.
require("telescope").load_extension "pomodori"
vim.keymap.set("n", "<leader>pt", function()
require("telescope").extensions.pomodori.timers()
end, { desc = "Manage Pomodori Timers"})
Please see the CONTRIBUTING guide from obsidian.nvim before submitting a pull request, as this repository is set up and managed in the same way.
And if you're feeling especially generous I always appreciate some coffee funds! β€οΈ