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
1 change: 1 addition & 0 deletions lua/opencode/config.lua
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@ M.defaults = {
},
output = {
filetype = 'opencode_output',
time_format = nil,
compact_assistant_headers = false,
rendering = {
markdown_debounce_ms = 250,
Expand Down
1 change: 1 addition & 0 deletions lua/opencode/types.lua
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,7 @@
---@field event_collapsing boolean

---@class OpencodeUIOutputConfig
---@field time_format string|nil # Custom os.date format for timestamps, e.g. '%m/%d %H:%M'. Uses fixed default when nil.
---@field tools { show_output: boolean, show_reasoning_output: boolean, use_folds: boolean, folding_threshold: number }
---@field rendering OpencodeUIOutputRenderingConfig
---@field max_messages integer|nil
Expand Down
19 changes: 16 additions & 3 deletions lua/opencode/util.lua
Original file line number Diff line number Diff line change
Expand Up @@ -224,11 +224,19 @@ function M.format_time(timestamp)
return ''
end

local config = require('opencode.config')
local time_format = config.ui.output.time_format

if time_format then
return os.date(time_format, timestamp)
end

local saved = os.setlocale('C', 'time')
local same_day = os.date('%Y-%m-%d') == os.date('%Y-%m-%d', timestamp)
local same_year = os.date('%Y') == os.date('%Y', timestamp)
local locale_time = vim.trim(os.date('%X', timestamp) or '')
os.setlocale(saved, 'time')

-- Keep output close to previous formatting by dropping seconds when present.
locale_time = locale_time:gsub('^(%d?%d:%d%d):%d%d(.*)$', '%1%2')
if locale_time == '' then
locale_time = vim.trim(os.date('%H:%M', timestamp) or '')
Expand All @@ -238,11 +246,16 @@ function M.format_time(timestamp)
return locale_time
end

saved = os.setlocale('C', 'time')
local date_part
if same_year then
return string.format('%s %s', os.date('%d %b', timestamp), locale_time)
date_part = os.date('%d %b', timestamp)
else
date_part = os.date('%d %b %Y', timestamp)
end
os.setlocale(saved, 'time')

return string.format('%s %s', os.date('%d %b %Y', timestamp), locale_time)
return string.format('%s %s', date_part, locale_time)
end

---@param timestamp number
Expand Down
17 changes: 13 additions & 4 deletions tests/unit/util_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -103,8 +103,17 @@ describe('util.format_time', function()
return os.time({ year = year, month = month, day = day, hour = hour or 0, min = min or 0, sec = sec or 0 })
end

local function c_locale_date(fmt, timestamp)
local saved = os.setlocale('C', 'time')
local result = os.date(fmt, timestamp)
os.setlocale(saved, 'time')
return result
end

local function compact_locale_time(timestamp)
local saved = os.setlocale('C', 'time')
local locale_time = vim.trim(os.date('%X', timestamp) or '')
os.setlocale(saved, 'time')
locale_time = locale_time:gsub('^(%d?%d:%d%d):%d%d(.*)$', '%1%2')
if locale_time == '' then
locale_time = vim.trim(os.date('%H:%M', timestamp) or '')
Expand Down Expand Up @@ -152,21 +161,21 @@ describe('util.format_time', function()
describe('other day timestamps', function()
it('formats yesterday with date prefix and locale time', function()
local result = util.format_time(yesterday)
local expected_prefix = os.date('%d %b', yesterday) .. ' '
local expected_prefix = c_locale_date('%d %b', yesterday) .. ' '
assert.is_true(vim.startswith(result, expected_prefix))
assert.equals(compact_locale_time(yesterday), result:sub(#expected_prefix + 1))
end)

it('formats last week with date prefix and locale time', function()
local result = util.format_time(last_week)
local expected_prefix = os.date('%d %b', last_week) .. ' '
local expected_prefix = c_locale_date('%d %b', last_week) .. ' '
assert.is_true(vim.startswith(result, expected_prefix))
assert.equals(compact_locale_time(last_week), result:sub(#expected_prefix + 1))
end)

it('formats future date with full date and locale time', function()
local result = util.format_time(next_year)
local expected_prefix = os.date('%d %b %Y', next_year) .. ' '
local expected_prefix = c_locale_date('%d %b %Y', next_year) .. ' '
assert.is_true(vim.startswith(result, expected_prefix))
assert.equals(compact_locale_time(next_year), result:sub(#expected_prefix + 1))
assert.matches('%d%d%d%d', result)
Expand Down Expand Up @@ -230,7 +239,7 @@ describe('util.format_time', function()
if os.date('%Y-%m-%d', early_tomorrow) == os.date('%Y-%m-%d') then
assert.equals(compact_locale_time(early_tomorrow), early_result)
else
local expected_prefix = os.date('%d %b', early_tomorrow) .. ' '
local expected_prefix = c_locale_date('%d %b', early_tomorrow) .. ' '
assert.is_true(vim.startswith(early_result, expected_prefix))
assert.equals(compact_locale_time(early_tomorrow), early_result:sub(#expected_prefix + 1))
end
Expand Down
Loading