disast.rs :: journal

for some reason I really like these things

neovim implementation

Highlights

I had to figure out a few things for this:

Implementation

This uses the lua interface for neovim, it's contained in three files:

 
 -- lua/bespoke/pomodoro.lua 
 local M = {} 
 
 M.want = function(name) 
   local out; if xpcall( 
     function() out = require(name) end, 
     function(e) out = e end) 
   then return out -- success 
   else return nil, out end -- error 
 end 
 
 local STOPPED = 0 
 local RUNNING = 1 
 
 M.data = { 
   notifier = "notify-send", 
   status = STOPPED, 
   seconds_left = 0, 
   timer = nil, 
   timer_type = "MAIN" -- or "BREAK" 
 } 
 
 M.finish = function() 
   M.notify("timer finished") 
   M.data.status = STOPPED 
   M.data.seconds_left = 0 
 end 
 
 M.start = function(seconds) 
   if M.data.status == RUNNING then 
     vim.notify("timer already running") 
   else 
     M.data.status = RUNNING 
     M.data.seconds_left = seconds 
     M.data.timer = vim.uv.new_timer() 
     M.notify("timer started") 
     M.data.timer:start(1000, 0, function() 
       if M.data.seconds_left < 0 then 
         M.data.timer:stop() 
         M.data.status = STOPPED 
         M.notify("timer finished") 
       elseif M.data.status == RUNNING then 
         M.data.seconds_left = M.data.seconds_left - 1 
       end 
     end) 
     M.data.timer:set_repeat(1000) 
   end 
 end 
 
 M.notify = function(msg) 
   vim.system({M.data.notifier, msg}) 
 end 
 
 M.pause = function() 
   M.data.status = STOPPED 
   M.notify("timer paused") 
 end 
 
 M.string = function() 
   local sec = M.data.seconds_left 
   local stat = "" 
   if M.data.status == RUNNING then 
     stat = "running: " 
   else 
     stat = "stopped: " 
   end 
   return stat .. string.format("%02.0f:%02.0f", sec / 60, sec % 60) 
 end 
 
 M.toggle = function() 
   if M.data.status == RUNNING then 
     M.data.status = STOPPED 
   else 
     M.start(25 * 60) 
   end 
 end 
 
 M.configure = function() 
   local statusline = M.want("bespoke.statusline") 
   if statusline then 
     vim.notify("registering statusline callback") 
     statusline.add_callback(M.string) 
   end 
 
   local wk = M.want("which-key") 
   if wk then 
     wk.add({ 
       {"<leader>p", group = "pomo" }, 
       {"<leader>ps", function() M.start(25 * 60) end, desc = "start main timer"}, 
       {"<leader>pb", function() M.start(5 * 60) end, desc = "start break timer"}, 
       {"<leader>pt", function() M.pause() end, desc = "pause timer"}, 
       {"<leader>pk", function() M.finish() end, desc = "kill timer"}, 
     }) 
   end 
 end 
 return M 
 

I also ended up writing some statusline logic

 
 -- lua/bespoke/statusline.lua 
 local M = {} 
 
 M.data = { 
   left = "%<%f %h%w%m%r", 
   right = "%-14.(%l,%c%V%) %P", 
   callbacks = {}, -- callbacks which evaluate to strings. Appends to right-side. 
   timer = nil, 
   computed = nil 
 } 
 
 M.eval = function() 
   local result = "" 
   for _, v in ipairs(M.data.callbacks) do 
    result = result .. " " .. v() 
   end 
   return result 
 end 
 
 M.configure = function() 
   M.data.computed = table.concat({ 
    M.data.left, 
    "%=", 
    "%{%v:lua.statusline.eval()%} :: ", 
    M.data.right 
   },'') 
   M.data.timer = vim.uv.new_timer() 
   M.data.timer:start(1000, 0, function() 
    vim.schedule(function() vim.cmd("redrawstatus") end) 
   end) 
   M.data.timer:set_repeat(1000) 
   vim.o.statusline = M.data.computed 
 end 
 
 M.add_callback = function(cb) 
  table.insert(M.data.callbacks, cb) 
 end 
 
 return M 
 

And to bring it all together, here's the snippet of my init.lua

 
 -- init.lua 
 statusline = require "bespoke.statusline" 
 pomodoro = require "bespoke.pomodoro" 
 -- ... snip, configure whichkey plugin here ... -- 
 pomodoro.configure() -- registers callback with statusline, sets up keybinds 
 statusline.configure() -- registers statusline refresh loop 
 
journal.html ::