Skip to content

πŸ†• ⏱️ A simple, customizable pomodoro timer for Neovim, written in Lua, with nvim-notify, lualine, and telescope integrations

License

Notifications You must be signed in to change notification settings

epwalsh/pomo.nvim

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

pomo.nvim

Latest release Last commit Latest Neovim Made with Lua

A simple, customizable pomodoro timer plugin for Neovim, written in Lua.

demo

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.

Features

  • πŸͺΆ 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

Commands

  • :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.

Setup

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 πŸ‘‡
  },
}
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,
})

Configuration options

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" },
    },
  },
}

Defining custom notifiers

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. The time_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 = {} }

Integrations

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",
    },
  },
}

lualine screenshot

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"})

Contributing

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! ❀️

BuyMeACoffee

About

πŸ†• ⏱️ A simple, customizable pomodoro timer for Neovim, written in Lua, with nvim-notify, lualine, and telescope integrations

Topics

Resources

License

Stars

Watchers

Forks