Skip to content

Commit 0f6c9ee

Browse files
committed
fix: adjust indentation handling for Python 3.13+ built-in REPL
In Python 3.13 and later, the new REPL automatically adjusts indentation based on context when entering a new line, which can cause unexpected indentation errors when pasting pre-indented code. This change enables/fixes compatibility by utilizing or working around the new Paste Mode (F3) to disable auto-indentation and ensure smooth execution of pasted blocks.
1 parent 1d5c3a3 commit 0f6c9ee

File tree

3 files changed

+31
-2
lines changed

3 files changed

+31
-2
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ iron.setup {
4444
command = { "python3" }, -- or { "ipython", "--no-autoindent" }
4545
format = common.bracketed_paste_python,
4646
block_dividers = { "# %%", "#%%" },
47-
env = {PYTHON_BASIC_REPL = "1"} --this is needed for python3.13 and up.
47+
is_new_repl = true -- this must be set to true for Python 3.13 and later.
4848
}
4949
},
5050
-- set the file type of the newly created repl to ft

lua/iron/fts/common.lua

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ local is_windows = require("iron.util.os").is_windows
22
local extend = require("iron.util.tables").extend
33
local open_code = "\27[200~"
44
local close_code = "\27[201~"
5+
local paste_mode_code = "\x1bOR"
56
local cr = "\13"
67

78
local common = {}
@@ -58,7 +59,11 @@ common.format = function(repldef, lines)
5859

5960
-- passing the command is for python. this will not affect bracketed_paste.
6061
if repldef.format then
61-
return repldef.format(lines, { command = repldef.command })
62+
if repldef.is_new_repl then
63+
return repldef.format(lines, { command = repldef.command, is_new_repl = repldef.is_new_repl })
64+
else
65+
return repldef.format(lines, { command = repldef.command })
66+
end
6267
elseif #lines == 1 then
6368
new = lines
6469
else
@@ -98,6 +103,7 @@ common.bracketed_paste_python = function(lines, extras)
98103
local result = {}
99104

100105
local cmd = extras["command"]
106+
local is_new_repl = extras["is_new_repl"] or false
101107
local pseudo_meta = { current_buffer = vim.api.nvim_get_current_buf()}
102108
if type(cmd) == "function" then
103109
cmd = cmd(pseudo_meta)
@@ -155,6 +161,16 @@ common.bracketed_paste_python = function(lines, extras)
155161
table.insert(result, "\n")
156162
end
157163

164+
-- In Python 3.13 and later, the built-in REPL automatically
165+
-- adjusts indentation based on contextual information when
166+
-- a new line is entered. This behavior may cause unexpected
167+
-- indentation errors in some cases. Fortunately, the new
168+
-- REPL provides a Paste Mode, which disables automatic
169+
-- indentation and allows code to run smoothly.
170+
if is_new_repl and not (is_windows and result[1] and result[1] == "\r") then
171+
table.insert(result, 1, paste_mode_code)
172+
end
173+
158174
return result
159175
end
160176

lua/iron/lowlevel.lua

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ local providers = require("iron.providers")
66
local format = require("iron.fts.common").format
77
local view = require("iron.view")
88
local is_windows = require("iron.util.os").is_windows
9+
local paste_mode_code = "\x1bOR"
910

1011
--- Low level functions for iron
1112
-- This is needed to reduce the complexity of the user API functions.
@@ -191,6 +192,18 @@ ll.send_to_repl = function(meta, data)
191192
vim.fn.chansend(meta.job, dt)
192193
end
193194

195+
-- In Python 3.13 and later, the built-in REPL automatically
196+
-- adjusts indentation based on contextual information when
197+
-- a new line is entered. This behavior may cause unexpected
198+
-- indentation errors in some cases. Fortunately, the new
199+
-- REPL provides a Paste Mode, which disables automatic
200+
-- indentation and allows code to run smoothly.
201+
if dt[1] and string.find(dt[1], paste_mode_code) then
202+
vim.defer_fn(function()
203+
vim.fn.chansend(meta.job, paste_mode_code .. "\r")
204+
end, 200)
205+
end
206+
194207
if window ~= -1 then
195208
vim.api.nvim_win_set_cursor(window, {vim.api.nvim_buf_line_count(meta.bufnr), 0})
196209
end

0 commit comments

Comments
 (0)