Skip to content
Draft
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
4 changes: 0 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -208,10 +208,6 @@ require('opencode').setup({
undo = { '<C-u>', mode = { 'i', 'n' } }, -- Undo to selected message in timeline picker
fork = { '<C-f>', mode = { 'i', 'n' } }, -- Fork from selected message in timeline picker
},
history_picker = {
delete_entry = { '<C-d>', mode = { 'i', 'n' } }, -- Delete selected entry in the history picker
clear_all = { '<C-X>', mode = { 'i', 'n' } }, -- Clear all entries in the history picker
},
model_picker = {
toggle_favorite = { '<C-f>', mode = { 'i', 'n' } },
},
Expand Down
13 changes: 7 additions & 6 deletions lua/opencode/commands/handlers/session.lua
Original file line number Diff line number Diff line change
Expand Up @@ -588,12 +588,13 @@ function M.actions.timeline()
return
end

local timeline_picker = require('opencode.ui.timeline_picker')
timeline_picker.pick(user_messages, function(selected_msg)
if selected_msg then
require('opencode.ui.navigation').goto_message_by_id(selected_msg.info.id)
end
end)
require('opencode.ui.timeline_picker').pick(user_messages, {
callback = function(selected_msg)
if selected_msg then
require('opencode.ui.navigation').goto_message_by_id(selected_msg.info.id)
end
end,
})
end

---@param message_id? string
Expand Down
113 changes: 75 additions & 38 deletions lua/opencode/commands/handlers/workflow.lua
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,6 @@ local function get_active_session_or_warn(message)
return active_session
end

---@param command string
---@param args string[]|nil
local function schedule_slash_history(command, args)
local joined_args = args and table.concat(args, ' ') or ''
vim.schedule(function()
history.write('/' .. command .. ' ' .. joined_args)
end)
end

---@param args string[]|nil
---@return string
local function join_args(args)
Expand Down Expand Up @@ -115,36 +106,90 @@ function M.actions.quick_chat(message, range)
quick_chat.quick_chat(prompt, { context_config = ctx }, range)
end

---Refill the input buffer from a user message returned by the timeline picker.
---Open the opencode UI first when the input window is not mounted yet.
---@param message OpencodeMessage
local function refill_input_from_message(message)
local windows = state.windows
if not input_window.mounted(windows) then
session_runtime.open({ focus = 'input' })
windows = state.windows
end
if not input_window.mounted(windows) then
return
end
---@cast windows { input_win: integer, input_buf: integer }
if input_window.refill_prompt_from_message(message) then
input_window.focus_input()
end
end

---@param entries OpencodeHistoryEntry[]
local function pick_history_with(entries)
local messages = vim.tbl_map(function(entry)
return entry.message
end, entries)
require('opencode.ui.timeline_picker').pick(messages, {
title = 'Select History Entry',
callback = function(selected_msg)
if selected_msg then
refill_input_from_message(selected_msg)
end
end,
})
end

function M.actions.select_history()
require('opencode.ui.history_picker').pick()
local entries = history.read()
if #entries == 0 then
vim.notify('No history entries found', vim.log.levels.INFO)
return false
end
return pick_history_with(entries)
end

---@param prompt string|nil
local function restore_prompt_history_entry(prompt)
if not prompt then
---Refill the input buffer from a history entry reconstructed from the active
---session's user messages
---@param entry OpencodeHistoryEntry
local function restore_prompt_history_entry(entry)
local windows = state.windows
if not windows or not windows.input_buf or not input_window.mounted(windows) then
return
end
if input_window.refill_prompt_from_message(entry.message) then
input_window.focus_input()
end
end

input_window.set_content(prompt)
require('opencode.ui.mention').restore_mentions(state.windows.input_buf)
---@param draft string[]
local function restore_prompt_draft(draft)
if input_window.replace_input(draft) then
input_window.focus_input()
end
end

function M.actions.prev_history()
if not state.ui.is_visible() then
return
end

local prev_prompt = history.prev()
restore_prompt_history_entry(prev_prompt)
local entry = history.prev()
if entry then
restore_prompt_history_entry(entry)
end
end

function M.actions.next_history()
if not state.ui.is_visible() then
return
end

local next_prompt = history.next()
restore_prompt_history_entry(next_prompt)
local result = history.next()
if result and result.message then
restore_prompt_history_entry(result)
elseif result then
restore_prompt_draft(result)
end
end

local function has_custom_input()
Expand Down Expand Up @@ -282,16 +327,12 @@ M.actions.run_user_command = Promise.async(function(name, args)
return
end

state.api_client
:send_command(active_session.id, {
command = name,
arguments = join_args(args),
model = model,
agent = agent,
})
:and_then(function()
schedule_slash_history(name, args)
end)
state.api_client:send_command(active_session.id, {
command = name,
arguments = join_args(args),
model = model,
agent = agent,
})
end) --[[@as Promise<void> ]]
end)

Expand Down Expand Up @@ -381,15 +422,11 @@ M.actions.review = Promise.async(function(args)

state.session.set_active(new_session)
window_handler.actions.open_input():await()
state.api_client
:send_command(state.active_session.id, {
command = 'review',
arguments = join_args(args),
model = state.current_model,
})
:and_then(function()
schedule_slash_history('review', args)
end)
state.api_client:send_command(state.active_session.id, {
command = 'review',
arguments = join_args(args),
model = state.current_model,
})
end)

M.actions.add_visual_selection = Promise.async(
Expand Down
4 changes: 0 additions & 4 deletions lua/opencode/config.lua
Original file line number Diff line number Diff line change
Expand Up @@ -122,10 +122,6 @@ M.defaults = {
undo = { '<C-u>', mode = { 'i', 'n' }, desc = 'Undo to selected message' },
fork = { '<C-f>', mode = { 'i', 'n' }, desc = 'Fork from selected message' },
},
history_picker = {
delete_entry = { '<C-d>', mode = { 'i', 'n' }, desc = 'Delete selected history entries' },
clear_all = { '<C-X>', mode = { 'i', 'n' }, desc = 'Clear all history entries' },
},
model_picker = {
toggle_favorite = { '<C-f>', mode = { 'i', 'n' }, desc = 'Toggle model favorite' },
},
Expand Down
Loading
Loading