Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 48 additions & 0 deletions docs/configuration.org
Original file line number Diff line number Diff line change
Expand Up @@ -787,6 +787,53 @@ To change the highlight, override =@org.agenda.separator= hl group.
- Default: =false=
Should tags be hidden from all agenda views.

*** org_agenda_time_grid
:PROPERTIES:
:CUSTOM_ID: org_agenda_time_grid
:END:
- Type: ={ type: ('daily', 'weekly', 'require-timed', 'remove-match')[], times: number[], time_separator: string, time_label: string }=
- Default:
#+begin_src lua
{
type = { 'daily', 'today', 'require-timed' },
times = { 800, 1000, 1200, 1400, 1600, 1800, 2000 },
time_separator = '┄┄┄┄┄',
time_label = '┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄'
}
#+end_src

Settings for the time grid visible in agenda. To disable showing the time grid altogether, set [[#org_agenda_use_time_grid][org_agenda_use_time_grid]] to =false=.

- =type=: List of options where all have to apply to show the grid
- =daily= - Show grid in daily agenda (1 day view)
- =weekly= - Show grid in any agenda type
- =today= - Show grid only for today
- =require-timed= - Show grid only if day has any entries with time specification
- =remove-match= - Hide grid entries that overlap with the existing time slot taken by an agenda item
- =times=: List of times (in 24h format) to show on the grid. It should be integer value, example =1030= represents =10:30=
- =time_separator=: Value that is showed after the grid time as a separator
- =time_label=: Value that is showed after the =time_separator= to fill in the place that is usually for the agenda item title

To customize the label for the current time, check [[#org_agenda_current_time_string][org_agenda_current_time_string]]

*** org_agenda_use_time_grid
:PROPERTIES:
:CUSTOM_ID: org_agenda_use_time_grid
:END:
- Type: =boolean=
- Default: =true=
Show time grid in agenda. See [[#org_agenda_time_grid][org_agenda_time_grid]] for configuration options.

*** org_agenda_current_time_string
:PROPERTIES:
:CUSTOM_ID: org_agenda_current_time_string
:END:
- Type: =string=
- Default: =<- now -----------------------------------------------=
Label value for the current time in the agenda time grid.
See [[#org_agenda_time_grid][org_agenda_time_grid]] for time grid configuration or [[#org_agenda_use_time_grid][org_agenda_use_time_grid]] to disable the grid.


*** org_capture_templates
:PROPERTIES:
:CUSTOM_ID: org_capture_templates
Expand Down Expand Up @@ -2872,6 +2919,7 @@ The following highlight groups are used:
- =@org.agenda.deadline=: A item deadline in the agenda view - Parsed from =Error= (see note below)
- =@org.agenda.scheduled=: A scheduled item in the agenda view - Parsed from =DiffAdd= (see note below)
- =@org.agenda.scheduled_past=: A item past its scheduled date in the agenda view - Parsed from =WarningMsg= (see note below)
- =@org.agenda.time_grid=: Time grid line - Parsed from =WarningMsg= (see note below)
- =@org.agenda.day=: Highlight for all days in Agenda view - linked to =Statement=
- =@org.agenda.today=: Highlight for today in Agenda view - linked to =@org.bold=
- =@org.agenda.weekend=: Highlight for weekend days in Agenda view - linked to =@org.bold=
Expand Down
4 changes: 2 additions & 2 deletions lua/orgmode/agenda/agenda_item.lua
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ local hl_map = Highlights.get_agenda_hl_map()
local config = require('orgmode.config')
local FUTURE_DEADLINE_AS_WARNING_DAYS = math.floor(config.org_deadline_warning_days / 2)
local function add_padding(datetime)
if datetime:len() >= 11 then
if datetime:len() >= 10 then
return datetime .. ' '
end
return datetime .. string.rep('.', 11 - datetime:len()) .. ' '
return datetime .. ' ' .. config.org_agenda_time_grid.time_separator .. ' '
end

---@class OrgAgendaItem
Expand Down
20 changes: 19 additions & 1 deletion lua/orgmode/agenda/sorting_strategy.lua
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ local SortingStrategy = {}

---@class SortableEntry
---@field date OrgDate Available only in agenda view
---@field headline OrgHeadline
---@field headline? OrgHeadline
---@field index number Index of the entry in the fetched list
---@field is_day_match? boolean Is this entry a match for the given day. Available only in agenda view

Expand Down Expand Up @@ -53,6 +53,9 @@ end
---@param a SortableEntry
---@param b SortableEntry
function SortingStrategy.priority_down(a, b)
if not a.headline or not b.headline then
return
end
if a.headline:get_priority_sort_value() ~= b.headline:get_priority_sort_value() then
return a.headline:get_priority_sort_value() > b.headline:get_priority_sort_value()
end
Expand All @@ -77,6 +80,9 @@ end
---@param a SortableEntry
---@param b SortableEntry
function SortingStrategy.tag_up(a, b)
if not a.headline or not b.headline then
return
end
local a_tags = a.headline:tags_to_string(true)
local b_tags = b.headline:tags_to_string(true)
if a_tags == '' and b_tags == '' then
Expand Down Expand Up @@ -106,6 +112,9 @@ end
---@param a SortableEntry
---@param b SortableEntry
function SortingStrategy.todo_state_up(a, b)
if not a.headline or not b.headline then
return
end
local _, _, _, a_index = a.headline:get_todo()
local _, _, _, b_index = b.headline:get_todo()
if a_index and b_index then
Expand Down Expand Up @@ -134,6 +143,9 @@ end
---@param a SortableEntry
---@param b SortableEntry
function SortingStrategy.category_up(a, b)
if not a.headline or not b.headline then
return
end
if a.headline.file:get_category() ~= b.headline.file:get_category() then
return a.headline.file:get_category() < b.headline.file:get_category()
end
Expand All @@ -151,6 +163,9 @@ end
---@param a SortableEntry
---@param b SortableEntry
function SortingStrategy.category_keep(a, b)
if not a.headline or not b.headline then
return
end
if a.headline.file.index ~= b.headline.file.index then
return a.headline.file.index < b.headline.file.index
end
Expand Down Expand Up @@ -179,6 +194,9 @@ end
---@param a SortableEntry
---@param b SortableEntry
local fallback_sort = function(a, b)
if not a.headline or not b.headline then
return
end
if a.headline.file.index ~= b.headline.file.index then
return a.headline.file.index < b.headline.file.index
end
Expand Down
147 changes: 145 additions & 2 deletions lua/orgmode/agenda/types/agenda.lua
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ local utils = require('orgmode.utils')
local SortingStrategy = require('orgmode.agenda.sorting_strategy')
local Promise = require('orgmode.utils.promise')

---@alias OrgAgendaDay { day: OrgDate, agenda_items: OrgAgendaItem[], category_length: number, label_length: 0 }

---@class OrgAgendaTypeOpts
---@field files OrgFiles
---@field highlighter OrgHighlighter
Expand Down Expand Up @@ -51,6 +53,7 @@ local Promise = require('orgmode.utils.promise')
---@field remove_tags? boolean
---@field valid_filters? OrgAgendaFilter[]
---@field id? string
---@field private _grid_times { hour: number, min: number }[]
local OrgAgendaType = {}
OrgAgendaType.__index = OrgAgendaType

Expand Down Expand Up @@ -264,7 +267,12 @@ function OrgAgendaType:render(bufnr, current_line)
}))

for _, agenda_item in ipairs(agenda_day.agenda_items) do
agendaView:add_line(self:_build_line(agenda_item, agenda_day))
-- If there is an index value, this is an AgendaItem instance
if agenda_item.index then
agendaView:add_line(self:_build_line(agenda_item, agenda_day))
else
agendaView:add_line(self:_build_time_grid_line(agenda_item, agenda_day))
end
end
end

Expand Down Expand Up @@ -318,6 +326,140 @@ function OrgAgendaType:render(bufnr, current_line)
return self.view
end

---@param grid_line { real_date: OrgDate, is_same_day: boolean, is_now: boolean }
---@param agenda_day OrgAgendaDay
---@return OrgAgendaLine
function OrgAgendaType:_build_time_grid_line(grid_line, agenda_day)
local line = AgendaLine:new({
hl_group = '@org.agenda.time_grid',
metadata = {
date = grid_line.real_date,
},
})

line:add_token(AgendaLineToken:new({
content = ' ' .. utils.pad_right(' ', agenda_day.category_length),
}))
line:add_token(AgendaLineToken:new({
content = grid_line.real_date:format_time() .. ' ' .. config.org_agenda_time_grid.time_separator,
}))
line:add_token(AgendaLineToken:new({
content = grid_line.is_now and config.org_agenda_current_time_string or config.org_agenda_time_grid.time_label,
}))

return line
end

---@param date_range OrgDate[]
---@param agenda_day OrgAgendaDay
---@return { real_date: OrgDate, is_same_day: boolean, is_now: boolean }[]
function OrgAgendaType:_prepare_grid_lines(date_range, agenda_day)
if not config.org_agenda_use_time_grid then
return {}
end

local time_grid_opts = config.org_agenda_time_grid
if not time_grid_opts or not time_grid_opts.type or #time_grid_opts.type == 0 then
return {}
end

local today = false
local weekly = false
local daily = false
local require_timed = false
local remove_match = false

for _, t in ipairs(time_grid_opts.type) do
if t == 'daily' then
daily = true
end
if t == 'weekly' then
weekly = true
end
if t == 'today' then
today = true
end
if t == 'require-timed' then
require_timed = true
end
if t == 'remove-match' then
remove_match = true
end
end

local show_grid = (daily and #date_range == 1) or weekly
if not show_grid and today then
show_grid = agenda_day.day:is_today()
end

local same_day_agenda_items_with_time = {}

if require_timed or remove_match then
for _, agenda_item in ipairs(agenda_day.agenda_items) do
if agenda_item.is_same_day and agenda_item.real_date:has_time() then
table.insert(same_day_agenda_items_with_time, agenda_item)
end
end
end

if show_grid and require_timed then
show_grid = #same_day_agenda_items_with_time > 0
end

if not show_grid then
return {}
end

local grid_lines = {}
local now = Date.now()
for _, time in ipairs(self:_parse_grid_times()) do
local date = agenda_day.day:set({
hour = time.hour,
min = time.min,
date_only = false,
})
if remove_match then
for _, item in ipairs(same_day_agenda_items_with_time) do
if item.real_date:is_same(date) then
goto continue
end
end
end
if date:is_today() and date > now and (#grid_lines == 0 or grid_lines[#grid_lines].real_date < now) then
local now_line = {
real_date = now,
is_same_day = true,
is_now = true,
}
table.insert(grid_lines, now_line)
end
table.insert(grid_lines, {
real_date = date,
is_same_day = true,
is_now = false,
})

::continue::
end
return grid_lines
end

function OrgAgendaType:_parse_grid_times()
if self._grid_times then
return self._grid_times
end
local grid_times = {}
for _, time in ipairs(config.org_agenda_time_grid.times) do
local str = tostring(time)
table.insert(grid_times, {
min = tonumber(str:sub(#str - 1, #str)),
hour = tonumber(str:sub(1, #str - 2)),
})
end
self._grid_times = grid_times
return grid_times
end

---@private
---@param agenda_item OrgAgendaItem
---@param metadata table<string, any>
Expand Down Expand Up @@ -381,7 +523,7 @@ function OrgAgendaType:rerender_agenda_line(agenda_line, headline)
self.view:replace_line(agenda_line, line)
end

---@return { day: OrgDate, agenda_items: OrgAgendaItem[], category_length: number, label_length: 0 }[]
---@return OrgAgendaDay[]
function OrgAgendaType:_get_agenda_days()
local dates = self.from:get_range_until(self.to)
local agenda_days = {}
Expand Down Expand Up @@ -413,6 +555,7 @@ function OrgAgendaType:_get_agenda_days()
end
end

vim.list_extend(date.agenda_items, self:_prepare_grid_lines(dates, date))
date.agenda_items = self:_sort(date.agenda_items)
date.category_length = math.max(11, date.category_length + 1)
date.label_length = math.min(11, date.label_length)
Expand Down
6 changes: 6 additions & 0 deletions lua/orgmode/colors/highlights.lua
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,12 @@ function M.define_agenda_colors()
string.format('hi default %s guifg=%s ctermfg=%s', hlname, keyword_colors[type].gui, keyword_colors[type].cterm)
)
end
vim.cmd(
('hi default @org.agenda.time_grid guifg=%s ctermfg=%s'):format(
keyword_colors.warning.gui,
keyword_colors.warning.cterm
)
)

M.define_org_todo_keyword_colors()
end
Expand Down
9 changes: 9 additions & 0 deletions lua/orgmode/config/_meta.lua
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,12 @@
---@field org_agenda_todo_ignore_scheduled? OrgAgendaTodoIgnoreScheduledTypes
---@field org_agenda_todo_ignore_deadlines? OrgAgendaTodoIgnoreDeadlinesTypes

---@class OrgAgendaTimeGridOpts
---@field type ('daily' | 'weekly' | 'today' | 'require-timed' | 'remove-match')[]
---@field times number[]
---@field time_separator string
---@field time_label string

---@alias OrgAgendaCustomCommandType (OrgAgendaCustomCommandAgenda | OrgAgendaCustomCommandTags)

---@class OrgAgendaCustomCommand
Expand Down Expand Up @@ -211,6 +217,9 @@
---@field org_agenda_block_separator? string Separator for blocks in the agenda view. Default: '-'
---@field org_agenda_sorting_strategy? table<'agenda' | 'todo' | 'tags', OrgAgendaSortingStrategy[]> Sorting strategy for the agenda view. See docs for default value
---@field org_agenda_remove_tags? boolean If true, tags will be removed from the all agenda views. Default: false
---@field org_agenda_use_time_grid? boolean If true, Render time grid in agenda as set by org_agenda_time_grid. Default: true
---@field org_agenda_time_grid? OrgAgendaTimeGridOpts Agenda time grid configuration. Default: { type = { 'daily', 'today', 'require-timed' }, times = { 800, 1000, 1200, 1400, 1600, 1800, 2000 }, time_separator = '┄┄┄┄┄', time_label = '┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄' }
---@field org_agenda_current_time_string? string String to indicate current time on the time grid. Default: '<- now -----------------------------------------------'
---@field org_priority_highest? string | number Highest priority level. Default: 'A'
---@field org_priority_default? string | number Default priority level. Default: 'B'
---@field org_priority_lowest? string | number Lowest priority level. Default: 'C'
Expand Down
8 changes: 8 additions & 0 deletions lua/orgmode/config/defaults.lua
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,14 @@ local DefaultConfig = {
tags = { 'priority-down', 'category-keep' },
},
org_agenda_remove_tags = false,
org_agenda_time_grid = {
type = { 'daily', 'today', 'require-timed' },
times = { 800, 1000, 1200, 1400, 1600, 1800, 2000 },
time_separator = '┄┄┄┄┄',
time_label = '┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄',
},
org_agenda_current_time_string = '<- now -----------------------------------------------',
org_agenda_use_time_grid = true,
org_priority_highest = 'A',
org_priority_default = 'B',
org_priority_lowest = 'C',
Expand Down
Loading
Loading