~rbdr/nota.nvim

9e9e89d8556ecafa6b11ab21aa9ffab550f7f3ad — Ruben Beltran del Rio 3 months ago 2cc2944
Add tagging
5 files changed, 109 insertions(+), 6 deletions(-)

M README.md
M lua/keybinds.lua
M lua/notes.lua
M lua/tasks.lua
M plugin/nota.lua
M README.md => README.md +1 -0
@@ 91,6 91,7 @@ require('lazy').setup({
- `<leader>it`, `:NotaInsertTask`, Inserts a task at cursor location.
- `<leader>ct`, `:NotaCaptureTask`, Captures a new task into the inbox.
- `<leader>Tt`, `:NotaTagTask`, Adds a tag to the current task.
- `<leader>Rt`, `:NotaRemoveTagTask`, Removes a tag from the current task.
- `<leader>rt`, `:NotaRescheduleTaskToday`, Reschedules the task under the cursor to today.
- `<leader>rT`, `:NotaRescheduleTaskTomorrow`, Reschedules the task under the cursor to tomorrow.
- `<leader>rs`, `:NotaRescheduleTaskSomeday`, Reschedules the task under the cursor to someday.

M lua/keybinds.lua => lua/keybinds.lua +1 -0
@@ 28,6 28,7 @@ function Keybinds.bind()
  api.nvim_set_keymap('n', '<leader>it', '<cmd>NotaInsertTask<CR>', { noremap = true, silent = true })
  api.nvim_set_keymap('n', '<leader>ct', '<cmd>NotaCaptureTask<CR>', { noremap = true, silent = true })
  api.nvim_set_keymap('n', '<leader>Tt', '<cmd>NotaTagTask<CR>', { noremap = true, silent = true })
  api.nvim_set_keymap('n', '<leader>Rt', '<cmd>NotaRemoveTagTask<CR>', { noremap = true, silent = true })
  api.nvim_set_keymap('n', '<leader>rt', '<cmd>NotaRescheduleTaskToday<CR>', { noremap = true, silent = true })
  api.nvim_set_keymap('n', '<leader>rT', '<cmd>NotaRescheduleTaskTomorrow<CR>', { noremap = true, silent = true })
  api.nvim_set_keymap('n', '<leader>rs', '<cmd>NotaRescheduleTaskSomeday<CR>', { noremap = true, silent = true })

M lua/notes.lua => lua/notes.lua +3 -1
@@ 37,7 37,9 @@ end

--- Opens the daily note
function Notes.open_daily(date)
  date = date or os.date('%Y-%m-%d')
  if not date or date == '' then
    date = os.date('%Y-%m-%d')
  end
  local filename =  date .. '.md'
  open_periodic_note('daily', filename)
end

M lua/tasks.lua => lua/tasks.lua +101 -3
@@ 14,6 14,18 @@ local unchecked_important_pattern = '^(%s*)%* %[ %]'
local checked_pattern = '^(%s*)%- %[x%]'
local checked_important_pattern = '^(%s*)%* %[x%]'

local function is_open_task(line)
  return line:match(unchecked_pattern) or line:match(unchecked_important_pattern)
end

local function is_completed_task(line)
  return line:match(checked_pattern) or line:match(checked_important_pattern)
end

local function is_task(line)
    return is_open_task(line) or is_completed_task(line)
end

local function open(path)
  local parent = Util.directory_name(path)
  Util.ensure_directory_exists(parent)


@@ 24,10 36,37 @@ local function open_inbox()
  local path = Configuration.path_for(Configuration.configuration.tasks.inbox)
  open(path)
end

local function open_someday()
  local path = Configuration.path_for(Configuration.configuration.tasks.someday)
  open(path)
end

local function parse_tags(tag_string)
  local tags = {}
  for tag in tag_string:gmatch('([^,]+)') do
    table.insert(tags, tag)
  end
  return tags
end

local function table_contains_value(target_table, value)
  for _, table_value in ipairs(target_table) do
    if table_value == value then
        return true
    end
  end
  return false
end

local function remove_value(target_table, value)
  for i, table_value in ipairs(target_table) do
    if table_value == value then
      table.remove(target_table, i)
    end
  end
end

-------------------------------------------------------------------------------
-- Public Interface
-------------------------------------------------------------------------------


@@ 45,6 84,8 @@ function Tasks.toggle()
        line = line:gsub(checked_pattern, '%1- [ ]', 1)
    elseif line:match(checked_important_pattern) then
        line = line:gsub(checked_important_pattern, '%1* [ ]', 1)
    else
      api.nvim_err_writeln('Toggle completion only works on tasks')
    end

    api.nvim_buf_set_lines(0, line_number - 1, line_number, false, {line})


@@ 63,6 104,8 @@ function Tasks.toggle_importance()
        line = line:gsub(checked_pattern, '%1* [x]', 1)
    elseif line:match(checked_important_pattern) then
        line = line:gsub(checked_important_pattern, '%1- [x]', 1)
    else
      api.nvim_err_writeln('Toggle importance only works on tasks')
    end

    api.nvim_buf_set_lines(0, line_number - 1, line_number, false, {line})


@@ 83,8 126,63 @@ function Tasks.capture()
end

--- Tag a task
function Tasks.tag()
  error('Not yet implemented')
function Tasks.tag(tag)
  local line_number = api.nvim_win_get_cursor(0)[1]
  local line = api.nvim_get_current_line()
  if is_task(line) then
    local pattern = ':(.*):$'
    local tag_string = line:match(pattern) or ''
    if not tag or tag == '' then
      tag = vim.fn.input('Add new tag for task (' .. tag_string .. '): ')
      if not tag or tag == '' then
        return
      end
    end
    local tags = parse_tags(tag_string)
    if not table_contains_value(tags, tag) then
      table.insert(tags, tag)
      local new_tags = table.concat(tags, ',')
      if line:match(pattern) then
        line = line:gsub(pattern, ':' .. new_tags .. ':', 1)
      else
        line = line .. '    :' .. new_tags .. ':'
      end
      api.nvim_buf_set_lines(0, line_number - 1, line_number, false, {line})
    end
  else
    api.nvim_err_writeln('Tagging only works on tasks')
  end
end

--- Remove tag on a task
function Tasks.remove_tag(tag)
  local line_number = api.nvim_win_get_cursor(0)[1]
  local line = api.nvim_get_current_line()
  if is_task(line) then
    local pattern = ':(.*):$'
    local tag_string = line:match(pattern)
    if not tag_string then
      api.nvim_err_writeln('No tags to remove')
      return
    end

    if not tag or tag == '' then
      tag = vim.fn.input('Pick tag to remove (' .. tag_string .. '): ')
    end

    local tags = parse_tags(tag_string)
    remove_value(tags, tag)
    local new_tags = ''

    if #tags > 0 then
      new_tags = ':' .. table.concat(tags, ',') .. ':'
    end

    line = line:gsub(pattern, new_tags, 1):gsub('%s+$', '')
    api.nvim_buf_set_lines(0, line_number - 1, line_number, false, {line})
  else
    api.nvim_err_writeln('Tagging only works on tasks')
  end
end

--- Reschedule a task for today


@@ 121,7 219,7 @@ function Tasks.reschedule(new_date)
  local line = api.nvim_get_current_line()
  local filename = vim.fn.expand('%:t:r')

  if line:match(unchecked_pattern) or line:match(unchecked_important_pattern) then
  if is_open_task(line) then
    if Util.is_before_today(filename) and line:match(unchecked_pattern) then
      local rescheduled_line = line:gsub(unchecked_pattern, '%1- [>' .. new_date .. ']', 1)
      api.nvim_buf_set_lines(0, line_number - 1, line_number, false, {rescheduled_line})

M plugin/nota.lua => plugin/nota.lua +3 -2
@@ 53,7 53,7 @@ if configuration.default_keybinds then
end

-- Note Handling Commands
command('NotaOpenDailyNote', function() require('notes').open_daily() end, { nargs = 0 })
command('NotaOpenDailyNote', function(options) require('notes').open_daily(options.args) end, { nargs = '?' })
command('NotaOpenWeeklyNote', function() require('notes').open_weekly() end, { nargs = 0 })
command('NotaOpenMonthlyNote', function() require('notes').open_monthly() end, { nargs = 0 })
command('NotaOpenSeasonalNote', function() require('notes').open_seasonal() end, { nargs = 0 })


@@ 71,7 71,8 @@ command('NotaToggleTask', function() require('tasks').toggle() end, { nargs = 0 
command('NotaToggleTaskImportance', function() require('tasks').toggle_importance() end, { nargs = 0 })
command('NotaInsertTask', function() require('tasks').insert() end, { nargs = 0 })
command('NotaCaptureTask', function() require('tasks').capture() end, { nargs = 0 })
command('NotaTagTask', function() require('tasks').tag() end, { nargs = 0 })
command('NotaTagTask', function(options) require('tasks').tag(options.args) end, { nargs = '?' })
command('NotaRemoveTagTask', function(options) require('tasks').remove_tag(options.args) end, { nargs = '?' })
command('NotaRescheduleTaskToday', function() require('tasks').reschedule_for_today() end, { nargs = 0 })
command('NotaRescheduleTaskTomorrow', function() require('tasks').reschedule_for_tomorrow() end, { nargs = 0 })
command('NotaRescheduleTaskSomeday', function() require('tasks').reschedule_for_someday() end, { nargs = 0 })