A little helper for displaying TaskWarrior's tasks.
For now this plugin offers the following features:
- List of task as list of string to use in the Dashboard
- For current project and others
- Just a few most urgent tasks
You can install little-taskwarrior.nvim using your favorite package manager.
For example with Lazy:
{
"praczet/little-taskwarrior.nvim",
config = function()
require("little-taskwarrior").setup({ })
end,
}- TaskWarrior - it uses standard export command form it
- Dashboard-nvim - if you want to use it in a dashboard
--- Default configuration
M.config = {
--- configuration for the Dashboard
dashboard = {
--- task limit
limit = 5,
--- max number of columns
max_width = 50,
--- if > 0 then additional task (besides current project ones) will be added
non_project_limit = 5,
--- List of columns to be displayed
columns = {
"id",
"project",
"description",
"due",
"urgency",
},
--- List of replacements when getting lines for dashboard
project_replacements = {
["work."] = "w.",
["personal."] = "p.",
},
--- Section separator
sec_sep = ".",
--- Enable or disable section shortening
shorten_sections = true,
},
--- function to reload dashboard config
get_dashboard_config = nil,
--- toggle the logging
debug = true,
--- where information about taskwarrior project can be found
project_info = ".little-taskwarrior.json",
--- above urgency_threshold all task could be highlighted in
--- the different way
urgency_threshold = 9,
--- Highlights
highlight_groups ={
--- for the urgent tasks (above the threshold)
urgent = nil,
--- default style (highlight_groups) for tasks
not_urgnet =nil
}
}So for example to make the area of task list wider you can do:
{
"praczet/little-taskwarrior.nvim",
config = function()
require("little-taskwarrior").setup({
dashboard = {
max_width = 80
}
})
end,
}This section sets how the dashboard's part will be displayed.
Those two options are used to display how many tasks will be displayed. Why two?
It is connected to the project_info option and .little-taskwarrior.json
file.
If in the current folder there is no .little-taskwarrior.json file only
limit will be taken. If the .little-taskwarrior.json is present the limit
will be applied to the number of tasks in for that project and
non_project_limit will be used for all others tasks.
If in the folder (project folder or current folder) file named
.little-taskwarrior.json exists. This plugin will try to read project name:
For example:
{
"project": "eos"
}If it succeeds it will use it as project name therefore the display mode will be switched to project specific mode. Which means the first task will be taken for that specific project. And then (if configuration allows) other tasks will be loaded. You can see this in [Tasks list with a project file](###Tasks list with a project file)
Those two options are use to format project names and they can be used together.
project_replacements- list of replacements for project namesshorten_sections- switches shortening of sections
(because I like examples)
Let's assume that we have projects related to work and several projects
related to personal.
In the personal project we have projects like:
personal.dashboard-nvimpersonal.little-taskwarrior
So task could look like this:
task add "I need to do something" project:personal.dashboard-nvimBut instead of displaying personal.dashboard-nvim we want to display
p.dashboard-nvim
Then we can add replacements in the configuration:
project_replacements = {
["work."] = "w.",
["personal."] = "p.",
},Note
Replacements can by as regular expression
So let's say that your projects hierarchy is much more complex (multi-levels):
- personal.develop.ltw
- personal.develop.nbd
- personal.todos
- personal.health.wo
- personal.health.doc
- personal.health.admin
Of course you can project_replacements to make it more readable, but this
approach will force you to add each project (subproject) manually.
shorten_sections will do this job automatically. Before I will try explain how
does it work look how previous list will look like:
- personal.develop.ltw > p.d.ltw
- personal.develop.nbd > p.d.nbd
- personal.todos > p.todos
- personal.health.wo > p.h.wo
- personal.health.doc > p.h.doc
- personal.health.admin > p.h.adminSo, each section but last will be shortened to the first letter, the last section will remain unchanged.
Those two options are used to highlight urgent tasks. The urgency_threshold
set the threshold above which task is themed to be urgent. The task becomes
urgent when urgency >= urgency_threshold.
highlight_groups is used to set the style of the tasks. It has two keys:
urgent- style of urgent tasksnot_urgent- style of not urgent Tasks
By style I mean vim's highlight. If highlight_groups is n t set the
default values will be used.
urgent- based on default@keywordhighlightnot_urgent- based on defaultCommenthighlight
You can see how they are defined in dashboard.lua in function: get_default_hl_group
Note
For unforeseen 'bug' in the code, you can override single entries. For example:
{
"praczet/little-taskwarrior.nvim",
config = function()
require("little-taskwarrior").setup({
dashboard = {
max_width = 80
}
highlight_groups = {
not_urgent = {
italic=false,
}
}
})
end,
}This will just 'switch' off italic from default Comment highlight
Of course you can use it as you want. I mean you can get the list and print it.
lua print(vim.inspect(require("little-taskwarrior").get_dashboard_tasks()))Important
This method will display Tasks in the Dashboard but it will not allow to refresh
task list after command Task
Based on my dashboard.lua config (I am using LazyVim)
return {
{
"nvimdev/dashboard-nvim",
opts = function()
-- Getting dashboard tasks
local ltw = require("little-taskwarrior")
local tasks = ltw.get_dashboard_tasks()
local logo = [[
...:::...
.. --- ..
. (0 0) .
. \=/ .
.-----------------.
( ©ad.art )
'''''''''''''''''''
]]
local currentDate = os.date("%Y-%m-%d")
local padding = math.floor((10 - #currentDate) / 2)
local centeredDate = string.rep(" ", padding) .. currentDate
logo = logo .. "\n" .. centeredDate .. "\n"
local header = vim.split(logo, "\n")
if tasks ~= nil then
for _, t in ipairs(tasks) do
table.insert(header, t)
end
table.insert(header, "")
end
local opts = {
theme = "doom",
config = {
header = header,
-- ... There is more like center, footer etc.
},
}
return opts
end,
},
}Important
It will enable refreshing the task list after command Task, but it requires some
steps
Since dashboard-nvim does not support refreshing header you can use
config.get_dashboard_config. Like this:
{
"praczet/little-taskwarrior.nvim",
config = function()
require("little-taskwarrior").setup({
get_dashboard_config = function()
-- here function that will return options for dashboard
-- the same as in dashboard-nvim setup.
local ltw = require("little-taskwarrior")
local tasks = ltw.get_dashboard_tasks()
local logo = [[
...:::...
.. --- ..
. (0 0) .
. \=/ .
.-----------------.
( ©ad.art )
'''''''''''''''''''
]]
local currentDate = os.date("%Y-%m-%d")
local padding = math.floor((10 - #currentDate) / 2)
local centeredDate = string.rep(" ", padding) .. currentDate
logo = logo .. "\n" .. centeredDate .. "\n"
local header = vim.split(logo, "\n")
if tasks ~= nil then
for _, t in ipairs(tasks) do
table.insert(header, t)
end
table.insert(header, "")
end
local opts = {
theme = "doom",
config = {
header = header,
-- ... There is more like center, footer etc.
},
}
return opts
end,
end
})
end,
}This will enable refreshing after Task command.
Now you can change configuration of dashboard-nvim plugin, like this:
return {
{
"nvimdev/dashboard-nvim",
opts = require('little-taskwarrior').get_dashboard_config
}
}Warning
This mostly works, but sometimes little-taskwarrior was taking too long to
load and then dashboard-nvim loaded the default one (in my case LazyVim).
There are many ways to solve it. For example you can put for your dashboard-nvim
config the function as usual, and then the same function in
little-taskwarrior. I do not like this (in two places the same code). It
forces me to remember to change it in two places.
I suggest this (solution for LazyVim):
-
Add a file
fallback.luain~/.config/nvim/lua/local function fall_back() local next = require("next-birthday") local lines = next.birthdays("now") local ltw = require("little-taskwarrior") local tasks = ltw.get_dashboard_tasks() local logo = [[ ...:::... .. --- .. . (0 0) . . \=/ . .-----------------. ( ©ad.art ) ''''''''''''''''''' ]] local currentDate = os.date("%Y-%m-%d") local padding = math.floor((10 - #currentDate) / 2) local centeredDate = string.rep(" ", padding) .. currentDate logo = logo .. "\n" .. centeredDate .. "\n" local header = vim.split(logo, "\n") if lines ~= nil then for _, l in ipairs(lines) do table.insert(header, l) end end table.insert(header, "") if tasks ~= nil then for _, t in ipairs(tasks) do table.insert(header, t) end table.insert(header, "") end local opts = { theme = "doom", hide = { -- this is taken care of by lualine -- enabling this messes up the actual laststatus setting after loading a file statusline = false, }, config = { header = header, -- stylua: ignore } } return opts end return { fall_back = fall_back, }
-
In the
dashboard-nvimconfig use like this:--- this file contains my own Dashboard config local dashboard_config = require("fallback") return { { "nvimdev/dashboard-nvim", opts = dashboard_config.fall_back, }, }
-
In the
little-taskwarriorconfig use like this:local dashboard_config = require("fallback") return { { "praczet/little-taskwarrior.nvim", config = function() require("little-taskwarrior").setup({ get_dashboard_config = dashboard_config.fall_back, }) end, }, }
You can see my config files in config folder of my repository.
- feat: Shortening project names by separator
- feat: Highlight urgent tasks
- feat: Preview task
- feat: Add task from selection or for current line


