Skip to content

Commit 3119cae

Browse files
cameronrsudo-tee
authored andcommitted
fix(formatter): use longer codefence
Instead of disabling embedded markdown rendering, we can use a longer outer codefence. It did require regenerating all of the test data.
1 parent 57c7f22 commit 3119cae

22 files changed

+28
-33
lines changed

lua/opencode/ui/formatter.lua

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -627,24 +627,26 @@ end
627627
---@param language string
628628
function M._format_code(output, lines, language)
629629
output:add_empty_line()
630-
output:add_line('```' .. (language or ''))
630+
--- NOTE: use longer code fence because lines could contain ```
631+
output:add_line('`````' .. (language or ''))
631632
output:add_lines(util.sanitize_lines(lines))
632-
output:add_line('```')
633+
output:add_line('`````')
633634
end
634635

635636
---@param output Output Output object to write to
636637
---@param code string
637638
---@param file_type string
638639
function M._format_diff(output, code, file_type)
639640
output:add_empty_line()
640-
output:add_line('```' .. file_type)
641+
642+
--- NOTE: use longer code fence because code could contain ```
643+
output:add_line('`````' .. file_type)
641644
local lines = vim.split(code, '\n')
642645
if #lines > 5 then
643646
lines = vim.list_slice(lines, 6)
644647
end
645648

646649
for _, line in ipairs(lines) do
647-
line = util.replace_markdown_codefences(line)
648650
local first_char = line:sub(1, 1)
649651
if first_char == '+' or first_char == '-' then
650652
local hl_group = first_char == '+' and 'OpencodeDiffAdd' or 'OpencodeDiffDelete'
@@ -669,7 +671,7 @@ function M._format_diff(output, code, file_type)
669671
output:add_line(line)
670672
end
671673
end
672-
output:add_line('```')
674+
output:add_line('`````')
673675
end
674676

675677
---@param output Output Output object to write to

lua/opencode/util.lua

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -140,21 +140,14 @@ function M.strip_ansi(str)
140140
return (str:gsub('\27%[[%d;]*m', ''))
141141
end
142142

143-
---Replace markdown codeblock markers with ` ` `
144-
---@param str string: Input string
145-
---@return string replaced_str
146-
function M.replace_markdown_codefences(str)
147-
return (str:gsub('```', '` ` `'))
148-
end
149-
150143
---Strip ANSI escape sequences from all lines
151144
---@param lines table
152145
---@return table stripped_lines
153146
function M.sanitize_lines(lines)
154147
local stripped_lines = {}
155148
for _, line in pairs(lines) do
156149
-- vim.notify(line)
157-
table.insert(stripped_lines, M.replace_markdown_codefences(M.strip_ansi(line)))
150+
table.insert(stripped_lines, M.strip_ansi(line))
158151
end
159152

160153
return stripped_lines

tests/data/ansi-codes.expected.json

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

tests/data/api-abort.expected.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
{"timestamp":1761606463,"extmarks":[[1,2,0,{"virt_text_win_col":-3,"virt_text_hide":false,"virt_text_repeat_linebreak":false,"right_gravity":true,"priority":10,"ns_id":3,"virt_text":[["▌󰭻 ","OpencodeMessageRoleUser"],[" "],["USER","OpencodeMessageRoleUser"],["","OpencodeHint"],[" (2025-10-27 22:44:29)","OpencodeHint"],[" [msg_a27d8299d001nchmBunYlZcPyL]","OpencodeHint"]],"virt_text_pos":"win_col"}],[2,3,0,{"virt_text_win_col":-3,"virt_text_hide":false,"virt_text_repeat_linebreak":true,"right_gravity":true,"priority":4096,"ns_id":3,"virt_text":[["▌","OpencodeMessageRoleUser"]],"virt_text_pos":"win_col"}],[3,4,0,{"virt_text_win_col":-3,"virt_text_hide":false,"virt_text_repeat_linebreak":true,"right_gravity":true,"priority":4096,"ns_id":3,"virt_text":[["▌","OpencodeMessageRoleUser"]],"virt_text_pos":"win_col"}],[4,5,0,{"virt_text_win_col":-3,"virt_text_hide":false,"virt_text_repeat_linebreak":true,"right_gravity":true,"priority":4096,"ns_id":3,"virt_text":[["▌","OpencodeMessageRoleUser"]],"virt_text_pos":"win_col"}],[5,6,0,{"virt_text_win_col":-3,"virt_text_hide":false,"virt_text_repeat_linebreak":true,"right_gravity":true,"priority":4096,"ns_id":3,"virt_text":[["▌","OpencodeMessageRoleUser"]],"virt_text_pos":"win_col"}],[6,9,0,{"virt_text_win_col":-3,"virt_text_hide":false,"virt_text_repeat_linebreak":false,"right_gravity":true,"priority":10,"ns_id":3,"virt_text":[[" ","OpencodeMessageRoleAssistant"],[" "],["PLAN","OpencodeMessageRoleAssistant"],[" gpt-4.1","OpencodeHint"],[" (2025-10-27 22:44:29)","OpencodeHint"],[" [msg_a27d829f9002sfUFPslHq5P2b4]","OpencodeHint"]],"virt_text_pos":"win_col"}]],"lines":["","----","","","can generate 10 numbers?","","[a-empty.txt](a-empty.txt)","","----","","","You asked if I can generate 10 numbers, and you referenced reading an empty file (`a-empty.txt`). However, I'm currently in \"plan mode,\" which means I cannot write or modify any files—I'm only allowed to read, observe,","","> [!ERROR] The operation was aborted.",""],"actions":[]}
1+
{"extmarks":[[1,2,0,{"priority":10,"virt_text_hide":false,"right_gravity":true,"virt_text_repeat_linebreak":false,"ns_id":3,"virt_text":[["▌󰭻 ","OpencodeMessageRoleUser"],[" "],["USER","OpencodeMessageRoleUser"],["","OpencodeHint"],[" (2025-10-27 22:44:29)","OpencodeHint"],[" [msg_a27d8299d001nchmBunYlZcPyL]","OpencodeHint"]],"virt_text_pos":"win_col","virt_text_win_col":-3}],[2,3,0,{"priority":4096,"virt_text_hide":false,"right_gravity":true,"virt_text_repeat_linebreak":true,"ns_id":3,"virt_text":[["▌","OpencodeMessageRoleUser"]],"virt_text_pos":"win_col","virt_text_win_col":-3}],[3,4,0,{"priority":4096,"virt_text_hide":false,"right_gravity":true,"virt_text_repeat_linebreak":true,"ns_id":3,"virt_text":[["▌","OpencodeMessageRoleUser"]],"virt_text_pos":"win_col","virt_text_win_col":-3}],[4,5,0,{"priority":4096,"virt_text_hide":false,"right_gravity":true,"virt_text_repeat_linebreak":true,"ns_id":3,"virt_text":[["▌","OpencodeMessageRoleUser"]],"virt_text_pos":"win_col","virt_text_win_col":-3}],[5,6,0,{"priority":4096,"virt_text_hide":false,"right_gravity":true,"virt_text_repeat_linebreak":true,"ns_id":3,"virt_text":[["▌","OpencodeMessageRoleUser"]],"virt_text_pos":"win_col","virt_text_win_col":-3}],[6,9,0,{"priority":10,"virt_text_hide":false,"right_gravity":true,"virt_text_repeat_linebreak":false,"ns_id":3,"virt_text":[[" ","OpencodeMessageRoleAssistant"],[" "],["PLAN","OpencodeMessageRoleAssistant"],[" gpt-4.1","OpencodeHint"],[" (2025-10-27 22:44:29)","OpencodeHint"],[" [msg_a27d829f9002sfUFPslHq5P2b4]","OpencodeHint"]],"virt_text_pos":"win_col","virt_text_win_col":-3}]],"timestamp":1761708190,"actions":[],"lines":["","----","","","can generate 10 numbers?","","[a-empty.txt](a-empty.txt)","","----","","","You asked if I can generate 10 numbers, and you referenced reading an empty file (`a-empty.txt`). However, I'm currently in \"plan mode,\" which means I cannot write or modify any files—I'm only allowed to read, observe,","","> [!ERROR] The operation was aborted.",""]}

tests/data/api-error.expected.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
{"extmarks":[[1,2,0,{"virt_text_pos":"win_col","virt_text_hide":false,"virt_text":[["▌󰭻 ","OpencodeMessageRoleUser"],[" "],["USER","OpencodeMessageRoleUser"],["","OpencodeHint"],[" (2025-10-20 04:44:37)","OpencodeHint"],[" [msg_9ffef0129001CoCrBKemk7DqcU]","OpencodeHint"]],"right_gravity":true,"virt_text_win_col":-3,"priority":10,"ns_id":3,"virt_text_repeat_linebreak":false}],[2,3,0,{"virt_text_pos":"win_col","virt_text_hide":false,"virt_text":[["▌","OpencodeMessageRoleUser"]],"right_gravity":true,"virt_text_win_col":-3,"priority":4096,"ns_id":3,"virt_text_repeat_linebreak":true}],[3,4,0,{"virt_text_pos":"win_col","virt_text_hide":false,"virt_text":[["▌","OpencodeMessageRoleUser"]],"right_gravity":true,"virt_text_win_col":-3,"priority":4096,"ns_id":3,"virt_text_repeat_linebreak":true}],[4,5,0,{"virt_text_pos":"win_col","virt_text_hide":false,"virt_text":[["▌","OpencodeMessageRoleUser"]],"right_gravity":true,"virt_text_win_col":-3,"priority":4096,"ns_id":3,"virt_text_repeat_linebreak":true}],[5,6,0,{"virt_text_pos":"win_col","virt_text_hide":false,"virt_text":[["▌","OpencodeMessageRoleUser"]],"right_gravity":true,"virt_text_win_col":-3,"priority":4096,"ns_id":3,"virt_text_repeat_linebreak":true}],[6,9,0,{"virt_text_pos":"win_col","virt_text_hide":false,"virt_text":[[" ","OpencodeMessageRoleAssistant"],[" "],["PLAN","OpencodeMessageRoleAssistant"],[" claude-sonnet-4-5-20250929","OpencodeHint"],[" (2025-10-20 04:44:37)","OpencodeHint"],[" [msg_9ffef0160001eArLyAssT]","OpencodeHint"]],"right_gravity":true,"virt_text_win_col":-3,"priority":10,"ns_id":3,"virt_text_repeat_linebreak":false}],[7,16,0,{"virt_text_pos":"win_col","virt_text_hide":false,"virt_text":[[" ","OpencodeMessageRoleAssistant"],[" "],["PLAN","OpencodeMessageRoleAssistant"],[" claude-sonnet-4-5-20250929","OpencodeHint"],[" (2025-10-20 04:44:37)","OpencodeHint"],[" [msg_9ffef0170001s2OM00h2cDa94A]","OpencodeHint"]],"right_gravity":true,"virt_text_win_col":-3,"priority":10,"ns_id":3,"virt_text_repeat_linebreak":false}]],"timestamp":1761608289,"lines":["","----","","","test 3","","[diff-test.txt](diff-test.txt)","","----","","","This is some sample text","","> [!ERROR] Simulated: tool/file read failed for earlier assistant message","","----","","","> [!ERROR] AI_APICallError: Your credit balance is too low to access the Anthropic API. Please go to Plans & Billing to upgrade or purchase credits.",""],"actions":[]}
1+
{"timestamp":1761708190,"extmarks":[[1,2,0,{"virt_text_win_col":-3,"virt_text_hide":false,"right_gravity":true,"virt_text_repeat_linebreak":false,"ns_id":3,"priority":10,"virt_text":[["▌󰭻 ","OpencodeMessageRoleUser"],[" "],["USER","OpencodeMessageRoleUser"],["","OpencodeHint"],[" (2025-10-20 04:44:37)","OpencodeHint"],[" [msg_9ffef0129001CoCrBKemk7DqcU]","OpencodeHint"]],"virt_text_pos":"win_col"}],[2,3,0,{"virt_text_win_col":-3,"virt_text_hide":false,"right_gravity":true,"virt_text_repeat_linebreak":true,"ns_id":3,"priority":4096,"virt_text":[["▌","OpencodeMessageRoleUser"]],"virt_text_pos":"win_col"}],[3,4,0,{"virt_text_win_col":-3,"virt_text_hide":false,"right_gravity":true,"virt_text_repeat_linebreak":true,"ns_id":3,"priority":4096,"virt_text":[["▌","OpencodeMessageRoleUser"]],"virt_text_pos":"win_col"}],[4,5,0,{"virt_text_win_col":-3,"virt_text_hide":false,"right_gravity":true,"virt_text_repeat_linebreak":true,"ns_id":3,"priority":4096,"virt_text":[["▌","OpencodeMessageRoleUser"]],"virt_text_pos":"win_col"}],[5,6,0,{"virt_text_win_col":-3,"virt_text_hide":false,"right_gravity":true,"virt_text_repeat_linebreak":true,"ns_id":3,"priority":4096,"virt_text":[["▌","OpencodeMessageRoleUser"]],"virt_text_pos":"win_col"}],[6,9,0,{"virt_text_win_col":-3,"virt_text_hide":false,"right_gravity":true,"virt_text_repeat_linebreak":false,"ns_id":3,"priority":10,"virt_text":[[" ","OpencodeMessageRoleAssistant"],[" "],["PLAN","OpencodeMessageRoleAssistant"],[" claude-sonnet-4-5-20250929","OpencodeHint"],[" (2025-10-20 04:44:37)","OpencodeHint"],[" [msg_9ffef0160001eArLyAssT]","OpencodeHint"]],"virt_text_pos":"win_col"}],[7,16,0,{"virt_text_win_col":-3,"virt_text_hide":false,"right_gravity":true,"virt_text_repeat_linebreak":false,"ns_id":3,"priority":10,"virt_text":[[" ","OpencodeMessageRoleAssistant"],[" "],["PLAN","OpencodeMessageRoleAssistant"],[" claude-sonnet-4-5-20250929","OpencodeHint"],[" (2025-10-20 04:44:37)","OpencodeHint"],[" [msg_9ffef0170001s2OM00h2cDa94A]","OpencodeHint"]],"virt_text_pos":"win_col"}]],"lines":["","----","","","test 3","","[diff-test.txt](diff-test.txt)","","----","","","This is some sample text","","> [!ERROR] Simulated: tool/file read failed for earlier assistant message","","----","","","> [!ERROR] AI_APICallError: Your credit balance is too low to access the Anthropic API. Please go to Plans & Billing to upgrade or purchase credits.",""],"actions":[]}

0 commit comments

Comments
 (0)