-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
refactor: cleanup reminder and use stream for performance
- Loading branch information
Showing
1 changed file
with
29 additions
and
46 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,68 +1,51 @@ | ||
local gtable = require("gears.table") | ||
local notifs = require("util.notifs") | ||
local path = require("util.path") | ||
local read_async = require("util.file.read_async") | ||
local spawn = require("util.spawn") | ||
local stream = require("stream") | ||
local strings = require("util.strings") | ||
local tables = require("util.tables") | ||
|
||
---Return a table of permutations of extensions | ||
---Note: this boils down to ("%s%s"):format. It does *no* path manipulation. | ||
---@param filepath string|string[] | ||
---@param exts string[] | ||
---@param include_original boolean? Should `path` be included in the result? Default: true | ||
---@return string[] | ||
local function add_suffix(filepath, exts, include_original) | ||
include_original = include_original == nil and true or include_original -- default to true | ||
if type(filepath) == "table" then | ||
local ret = include_original and gtable.clone(filepath, false) or {} | ||
return stream | ||
.new(filepath) | ||
:map(function(p) -- Don't include original to remove duplicates | ||
return add_suffix(p, exts, false) | ||
end) | ||
:reduce(ret, gtable.merge) | ||
end | ||
return ( | ||
stream | ||
.new(exts) | ||
:map(function(ext) return ("%s%s"):format(filepath, ext) end) | ||
:toarray(include_original and { filepath } or nil) | ||
) | ||
end | ||
--- Only all caps or all lower case is allowed | ||
local home_reminder_paths = tables.map_val({ "reminder", ".reminder", ".todo", "todo" }, string.lower) | ||
local extensions = { ".txt", ".md" } | ||
-- These should be /todo, /reminder, ... | ||
local files_wo_extensions = add_suffix(path.sep, home_reminder_paths, false) | ||
local files_wo_extensions_allow_cap = | ||
gtable.join(files_wo_extensions, tables.map_val(files_wo_extensions, string.upper)) | ||
--- These should be /todo, /todo.txt, /todo.md, ... | ||
local allowed_files = add_suffix(files_wo_extensions_allow_cap, extensions, true) | ||
--- reminder/todo.txt, todo.txt, .reminder.md, ... | ||
local paths = add_suffix(tables.map_val(home_reminder_paths, path.get_home), gtable.join(extensions, allowed_files)) | ||
local index = 1 | ||
--- Note: the order of this matters, as the first one is the one that is used. | ||
--- PERF: I use todo more often than reminder, so I put it first, this saves ~30 iterations. | ||
local names = { "todo", "reminder" } | ||
local extensions = { ".md", ".txt" } | ||
|
||
local path_stream = stream | ||
.new(names) | ||
-- todo, .todo, .reminder, reminder | ||
:flatmap(function(p) return { p, "." .. p } end) | ||
-- todo, TODO, Todo, ... | ||
:flatmap(function(p) return { p:lower(), p:gsub("^%l", string.upper), p:upper() } end) | ||
-- todo, todo/index, ... | ||
:flatmap(function(p) return { p, path.join(p, "index") } end) | ||
--- todo, todo.txt, todo.md, todo/index.txt, todo/index.md, ... | ||
:flatmap(function(p) ---@param p string | ||
return stream.concat(stream.of(p), stream.new(extensions):map(function(e) return p .. e end)) | ||
end) | ||
-- /home/user/todo, /home/user/todo/index, ... | ||
:map(path.get_home) | ||
|
||
local function handler(content, _, fpath) | ||
if not content then -- Repeat until we find one. | ||
index = index + 1 -- Try the next one. | ||
if not paths[index] then return end | ||
return read_async(paths[index], handler) | ||
local next, done = path_stream:next() -- Try the next one. | ||
if done then return end -- there are no more | ||
return read_async(next, handler) | ||
end | ||
if #content == 0 or content:find("^%s*$") then return end -- just whitespace | ||
|
||
local msg = content:gsub("^\n*", ""):gsub("\n*$", ""):gsub("\n\n\n", "\n\n") | ||
return notifs.info(msg, { title = ("Reminder (%s)"):format(path.tildify(fpath)) }) | ||
end | ||
read_async(path_stream:next(), handler) | ||
|
||
--- Spawn the `todo` command to get the todo list | ||
spawn.async_success({ "todo", "count" }, function(stdout_count) | ||
if tonumber(stdout_count) == 0 then return end | ||
spawn.async_success({ "todo", "list" }, function(stdout) | ||
stdout_count = tonumber(stdout_count) | ||
if not stdout_count or stdout_count == 0 then return end | ||
return spawn.async_success({ "todo", "list" }, function(stdout) | ||
local out = strings.trim(stdout) | ||
if out == "" then return end | ||
return notifs.info(out, { title = "Todo" }) | ||
local todo_s = strings.pluralize("todo", stdout_count) | ||
return notifs.info(out, { title = ("You have %d %s"):format(stdout_count, todo_s) }) | ||
end) | ||
end) | ||
|
||
return read_async(paths[index], handler) |