Skip to content
53 changes: 53 additions & 0 deletions doc/orgmode.txt
Original file line number Diff line number Diff line change
Expand Up @@ -845,6 +845,59 @@ Separator used to separate multiple agenda views generated by
`@org.agenda.separator` hl group.


org_agenda_prefix_format *orgmode-org_agenda_prefix_format*

- Type: `{ agenda?: string, todo?: string, tags?: string, search?: string,
tags_todo?: string }`
- Default:
>lua
{
agenda = ' %-12:c%?t% s',
todo = ' %-12:c',
tags = ' %-12:c',
tags_todo = ' %-12:c',
search = ' %-12:c',
}
<

Format for the prefix of each line in the agenda view. The format string can
contain placeholders that will be replaced with actual values. Format of the
placeholder: `%[specifiers][variable]` or `%[specifiers](lua expression)`.

**Specifiers:**

- `-` - Left align the value (default is right align)
- `[number]` - Set fixed width for the value
- `?` - Optional placeholder. If the value is empty, the placeholder (and surrounding spaces) will be omitted.

**Variables:**

- `c` - Category of the headline
- `:c` - Category of the headline followed by a colon
- `s` - Planning info (Deadline, Scheduled, etc.)
- `t` - Time range (e.g. 10:00-11:00)
- `T` - Tags
- `e` - Effort property
- `l` - Headline level
- `b` - Breadcrumbs (parent headline titles separated by `->`)

**Lua expressions:** Anything inside `%()` will be evaluated as a Lua
expression. The expression has access to following variables:

- `headline` - |orgmode-orgheadline| object
- `item` - |orgmode-orgagendaitem| object (only in `agenda` view)
- `metadata` - Metadata table containing `category_length`

Example:

>lua
org_agenda_prefix_format = {
agenda = ' %-12:c %?t %s ',
todo = ' %-12:c %(headline:get_property("PRIORITY") or "C") '
}
<


org_agenda_remove_tags *orgmode-org_agenda_remove_tags*

- Type: `boolean`
Expand Down
50 changes: 50 additions & 0 deletions docs/configuration.org
Original file line number Diff line number Diff line change
Expand Up @@ -788,6 +788,56 @@ Separator used to separate multiple agenda views generated by
[[#org_agenda_custom_commands][org_agenda_custom_commands]].
To change the highlight, override =@org.agenda.separator= hl group.

*** org_agenda_prefix_format
:PROPERTIES:
:CUSTOM_ID: org_agenda_prefix_format
:END:
- Type: ={ agenda?: string, todo?: string, tags?: string, search?: string, tags_todo?: string }=
- Default:
#+begin_src lua
{
agenda = ' %-12:c%?t% s',
todo = ' %-12:c',
tags = ' %-12:c',
tags_todo = ' %-12:c',
search = ' %-12:c',
}
#+end_src

Format for the prefix of each line in the agenda view.
The format string can contain placeholders that will be replaced with actual values.
Format of the placeholder: =%[specifiers][variable]= or =%[specifiers](lua expression)=.

*Specifiers:*
- =-= - Left align the value (default is right align)
- =[number]= - Set fixed width for the value
- =?= - Optional placeholder. If the value is empty, the placeholder (and surrounding spaces) will be omitted.

*Variables:*
- =c= - Category of the headline
- =:c= - Category of the headline followed by a colon
- =s= - Planning info (Deadline, Scheduled, etc.)
- =t= - Time range (e.g. 10:00-11:00)
- =T= - Tags
- =e= - Effort property
- =l= - Headline level
- =b= - Breadcrumbs (parent headline titles separated by =->=)

*Lua expressions:*
Anything inside =%()= will be evaluated as a Lua expression.
The expression has access to following variables:
- =headline= - [[#org-headline][OrgHeadline]] object
- =item= - [[#org-agenda-item][OrgAgendaItem]] object (only in =agenda= view)
- =metadata= - Metadata table containing =category_length=

Example:
#+begin_src lua
org_agenda_prefix_format = {
agenda = ' %-12:c %?t %s ',
todo = ' %-12:c %(headline:get_property("PRIORITY") or "C") '
}
#+end_src

*** org_agenda_remove_tags
:PROPERTIES:
:CUSTOM_ID: org_agenda_remove_tags
Expand Down
40 changes: 26 additions & 14 deletions lua/orgmode/agenda/agenda_item.lua
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ end
---@field is_in_date_range boolean
---@field date_range_days number
---@field label string
---@field time string
---@field marker string
---@field index number
local AgendaItem = {}

Expand Down Expand Up @@ -77,6 +79,8 @@ function AgendaItem:_process()
end

function AgendaItem:_generate_data()
self.time = self.headline_date:has_time() and self:_format_time(self.headline_date) or ''
self.marker = self:_generate_marker()
self.label = self:_generate_label()
end

Expand Down Expand Up @@ -152,19 +156,18 @@ function AgendaItem:_is_valid_for_date()

return false
end

function AgendaItem:_generate_label()
local time = self.headline_date:has_time() and add_padding(self:_format_time(self.headline_date)) or ''
---@private
function AgendaItem:_generate_marker()
if self.headline_date:is_deadline() then
if self.is_same_day then
return time .. 'Deadline:'
return 'Deadline:'
end
return self.headline_date:humanize(self.date) .. ':'
end

if self.headline_date:is_scheduled() then
if self.is_same_day then
return time .. 'Scheduled:'
return 'Scheduled:'
end

local diff = math.abs(self.date:diff(self.headline_date))
Expand All @@ -174,21 +177,30 @@ function AgendaItem:_generate_label()

if self.headline_date.is_date_range_start then
if not self.is_in_date_range then
return time
return ''
end
local range = string.format('(%d/%d):', self.date:diff(self.headline_date) + 1, self.date_range_days)
if not self.is_same_day then
return range
end
return time .. range
return string.format('(%d/%d):', self.date:diff(self.headline_date) + 1, self.date_range_days)
end

if self.headline_date.is_date_range_end then
local range = string.format('(%d/%d):', self.date_range_days, self.date_range_days)
return time .. range
return string.format('(%d/%d):', self.date_range_days, self.date_range_days)
end

return ''
end

function AgendaItem:_generate_label()
local include_time = self.time ~= ''
if (self.headline_date:is_deadline() or self.headline_date:is_scheduled()) and not self.is_same_day then
include_time = false
end

if self.headline_date.is_date_range_start and not self.is_in_date_range and not self.is_same_day then
include_time = false
end

return time
local time = include_time and add_padding(self.time) or ''
return time .. self.marker
end

---@private
Expand Down
10 changes: 7 additions & 3 deletions lua/orgmode/agenda/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,9 @@ function Agenda:_build_custom_commands()
end
local custom_commands = {}
---@param opts OrgAgendaCustomCommandType
local get_type_opts = function(opts, id)
---@param parent_opts? table
local get_type_opts = function(opts, id, parent_opts)
parent_opts = parent_opts or {}
local opts_by_type = {
agenda = {
span = opts.org_agenda_span,
Expand Down Expand Up @@ -153,7 +155,9 @@ function Agenda:_build_custom_commands()
opts_by_type[opts.type].tag_filter = opts.org_agenda_tag_filter_preset
opts_by_type[opts.type].category_filter = opts.org_agenda_category_filter_preset
opts_by_type[opts.type].highlighter = self.highlighter
opts_by_type[opts.type].remove_tags = opts.org_agenda_remove_tags
opts_by_type[opts.type].remove_tags = utils.if_nil(opts.org_agenda_remove_tags, parent_opts.org_agenda_remove_tags)
opts_by_type[opts.type].org_agenda_prefix_format =
utils.if_nil(opts.org_agenda_prefix_format, parent_opts.org_agenda_prefix_format)
opts_by_type[opts.type].id = id

return opts_by_type[opts.type]
Expand All @@ -165,7 +169,7 @@ function Agenda:_build_custom_commands()
action = function()
local views = {}
for i, agenda_type in ipairs(command.types) do
local opts = get_type_opts(agenda_type, ('%s_%s_%d'):format(shortcut, agenda_type.type, i))
local opts = get_type_opts(agenda_type, ('%s_%s_%d'):format(shortcut, agenda_type.type, i), command)
if not opts then
utils.echo_error('Invalid custom agenda command type ' .. agenda_type.type)
break
Expand Down
22 changes: 16 additions & 6 deletions lua/orgmode/agenda/types/agenda.lua
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ local AgendaItem = require('orgmode.agenda.agenda_item')
local AgendaView = require('orgmode.agenda.view.init')
local AgendaLine = require('orgmode.agenda.view.line')
local AgendaLineToken = require('orgmode.agenda.view.token')
local Formatter = require('orgmode.agenda.view.formatter')
local ClockReport = require('orgmode.clock.report')
local utils = require('orgmode.utils')
local SortingStrategy = require('orgmode.agenda.sorting_strategy')
Expand Down Expand Up @@ -52,6 +53,7 @@ local Promise = require('orgmode.utils.promise')
---@field sorting_strategy? OrgAgendaSortingStrategy[]
---@field remove_tags? boolean
---@field valid_filters? OrgAgendaFilter[]
---@field org_agenda_prefix_format? table
---@field id? string
---@field private _grid_times { hour: number, min: number }[]
local OrgAgendaType = {}
Expand Down Expand Up @@ -79,6 +81,7 @@ function OrgAgendaType:new(opts)
sorting_strategy = opts.sorting_strategy or vim.tbl_get(config.org_agenda_sorting_strategy, 'agenda') or {},
id = opts.id,
remove_tags = utils.if_nil(opts.remove_tags, config.org_agenda_remove_tags),
org_agenda_prefix_format = opts.org_agenda_prefix_format,
}
data.valid_filters = vim.tbl_filter(function(filter)
return filter and true or false
Expand Down Expand Up @@ -246,6 +249,10 @@ function OrgAgendaType:render(bufnr, current_line)
end
local agenda_days = self:_get_agenda_days()

local prefix_formats = self.org_agenda_prefix_format or config.org_agenda_prefix_format
local prefix_format = prefix_formats.agenda
local compiled_prefix = Formatter.compile(prefix_format)

local agendaView = AgendaView:new({ bufnr = self.bufnr, highlighter = self.highlighter })
agendaView:add_line(AgendaLine:single_token({
content = self:_get_title(),
Expand All @@ -269,7 +276,7 @@ function OrgAgendaType:render(bufnr, current_line)
for _, agenda_item in ipairs(agenda_day.agenda_items) do
-- 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))
agendaView:add_line(self:_build_line(agenda_item, agenda_day, compiled_prefix))
else
agendaView:add_line(self:_build_time_grid_line(agenda_item, agenda_day))
end
Expand Down Expand Up @@ -496,8 +503,9 @@ end
---@private
---@param agenda_item OrgAgendaItem
---@param metadata table<string, any>
---@param compiled_prefix? OrgAgendaFormatterSegment[]
---@return OrgAgendaLine
function OrgAgendaType:_build_line(agenda_item, metadata)
function OrgAgendaType:_build_line(agenda_item, metadata, compiled_prefix)
local headline = agenda_item.headline
local item_hl_group = agenda_item:get_hlgroup()
local line = AgendaLine:new({
Expand All @@ -510,11 +518,13 @@ function OrgAgendaType:_build_line(agenda_item, metadata)
label_length = metadata.label_length,
},
})

local prefix_formats = self.org_agenda_prefix_format or config.org_agenda_prefix_format
local prefix_format = compiled_prefix or Formatter.compile(prefix_formats.agenda)
local prefix = Formatter.format(prefix_format, agenda_item, metadata)

line:add_token(AgendaLineToken:new({
content = ' ' .. utils.pad_right(('%s:'):format(headline:get_category()), metadata.category_length),
}))
line:add_token(AgendaLineToken:new({
content = utils.pad_right(agenda_item.label, metadata.label_length),
content = prefix,
}))
local todo = headline:get_todo()
if todo then
Expand Down
1 change: 1 addition & 0 deletions lua/orgmode/agenda/types/search.lua
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ OrgAgendaSearchType.__index = OrgAgendaSearchType
---@param opts OrgAgendaSearchTypeOpts
function OrgAgendaSearchType:new(opts)
opts.todo_only = false
opts.prefix_key = 'search'
opts.subheader = 'Press "r" to update search'
setmetatable(self, { __index = OrgAgendaTodosType })
local obj = OrgAgendaTodosType:new(opts)
Expand Down
1 change: 1 addition & 0 deletions lua/orgmode/agenda/types/tags.lua
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ OrgAgendaTagsType.__index = OrgAgendaTagsType
---@param opts OrgAgendaTagsTypeOpts
function OrgAgendaTagsType:new(opts)
opts.todo_only = opts.todo_only or false
opts.prefix_key = 'tags'
opts.sorting_strategy = opts.sorting_strategy or vim.tbl_get(config.org_agenda_sorting_strategy, 'tags') or {}
if not opts.id then
opts.subheader = 'Press "r" to update search'
Expand Down
1 change: 1 addition & 0 deletions lua/orgmode/agenda/types/tags_todo.lua
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ function OrgAgendaTagsTodoType:new(opts)
return nil
end
setmetatable(obj, self)
obj.prefix_key = 'tags_todo'
return obj
end

Expand Down
Loading
Loading