Commit Graph
3 Commits
Author SHA1 Message Date
prxnvt 9ac06dd8cc UI: Python mode in the formula bar
Python cells get an editing mode of their own in the formula bar, in the
code editor (monospace, Python colours). It starts with Ctrl+Alt+Shift+P
(Cmd+Option+Shift+P on macOS), with =PY then Tab as in Excel, or by
editing a Python cell (F2, a double-click, a click on the formula bar);
typing over a Python cell still replaces it. The shortcut again leaves
Python mode and keeps the text as an ordinary entry.

In Python mode Enter starts a new line with the indentation, Tab and
Shift+Tab indent, Ctrl+Enter (Cmd+Enter on macOS) commits the code
through python.set and Esc cancels. Every commit path of a Python edit
goes through python.set, the formula bar's Enter button and a click on
the sheet included. When the command refuses the code (longer than a
cell holds), its message shows and the edit stays open with the code as
typed. A locked cell on a protected sheet is refused before a draft
exists, and a draft whose cell protection locks while it is open is
dropped with the warning, as an ordinary edit is (#2945). A Python cell's code committed unchanged writes
nothing (no undo step), as F2 then Enter on any other cell does. With
all the code deleted, the commit clears a Python cell through cell.set,
as an empty entry clears any other cell (code of spaces is still code);
on another cell it writes nothing. The formula bar shows while a Python
edit is open, also when View > Formula Bar hides it, since Python mode
edits only there. A Python draft records the window it was typed in,
as an ordinary draft does, so it is committed in that window when
another comes forward.

Python mode replaces the route that sent a changed edit of a Python
cell's code through python.set (EditState.code_edit and
commit_code_edit): every such edit now starts in Python mode, so that
route is removed, and leaving Python mode commits the text as an
ordinary entry through cell.set. The UI tests of that route commit with
Ctrl+Enter, since Enter starts a new line in Python mode; the guard that
keeps a column completion out of a code edit now reads Python mode.

The keys are applied in input order with the typing, on main's
apply_in_order: the code editor takes a set of stop keys from its caller
(apply_in_order_until), so Ctrl+Enter, Esc and the shortcut act on the
text as it was when they were pressed. After a key the text field acts
on (select all), a stop key waits for the next pass with the editor's
keys before it, so select all, Tab and Ctrl+Enter in one frame commits
the indented code. Keyboard events after a stop key in the same pass are
dropped. code_field is the editor without its frame, for the bar.

The PY badge beside fx shows in Python mode and on a selected Python
cell; clicking it switches Python mode as the shortcut does.
ui.pythonMode {on?} does the same from the control channel, without a
dialog, and engine.commands lists it. ui.inspect reports editor.python,
and leaves a Python draft's code out (text null, hidden true) while its
cell's code is hidden on a protected sheet, checked when it is called:
a protection command earlier in the same batch runs before the next
frame. Theme tokens badge_py,
on_badge, sheet_py_tag and on_sheet_py_tag join the contrast test.

A draft, Python or not, records its sheet's identity (Sheet::uid) when
it starts and follows that sheet, since commands that run while it is
open (sheet.move, home.insertSheet, home.deleteSheet, their undo, a
macro, a tool that adds a report sheet) change which sheet sits at its
index. A commit goes to the draft's own sheet; before, a draft committed
after a sheet was inserted before its own went into the inserted sheet,
an ordinary draft as well. A draft whose sheet is gone is dropped with a
message, as one whose cell protection locks is. ui.inspect checks for
hidden code on the draft's own sheet, and once that sheet is gone it
leaves out a Python draft, or one that began on a Python cell.
2026-11-01 21:02:03 -05:00
prxnvt 6c478475e4 UI: a Python code edit is never completed from the column
While a Python cell's code was edited (F2 or the formula bar), typing at the
end of the code could offer AutoComplete from a text value in the same column,
and Enter then committed that text as the code. The editor no longer offers a
completion during a code edit, and committing a code edit ignores one.
2026-11-01 14:07:15 -05:00
prxnvt c6c54c57e6 Engine: python.set makes a Python cell; this build stores code and
doesn't run it

python.set {cell?, code, output?: object|value} makes the cell (the
active cell by default) a Python cell, keeping its style and taking a
formula and its spill away. `output` is the return type Microsoft
documents for PY(): an Excel value (the default) or a Python object;
without it a Python cell keeps the one it had. The code must fit in
Excel's 8,192-character formula once written as PY(...), quotes doubled
and literals joined, so the command checks the encoded formula rather
than a character count. A table's header row refuses Python (it holds
the column's name, as Excel keeps formulas out of headers), and a locked
cell on a protected sheet refuses it through the usual protection check.

Nothing runs Python here. Unchanged code keeps its cached result and
value; new or changed code shows #BLOCKED!. One undo step takes the cell
back.

Sheet::clear_spill removes the spilled values inside a range with work
bounded by the values stored, not by the range's size.

In the interface, F2, a double click or the formula bar on a Python cell
edits its code, and a changed text is committed through python.set,
which keeps the return type; through cell.set it would have replaced the
Python cell with an ordinary cell holding the code as text. Typing over
a Python cell replaces it, as typing over a formula does, and committing
the code unchanged writes nothing. Deleting all the code clears the
cell through cell.set, as an empty entry clears any other cell; code
of spaces is still code.

Tests: the code and return type in cell.get, #BLOCKED! for new code,
cached results kept for unchanged code, the active-cell default, undo,
refused params (missing or non-text code, a bad cell, a bad return
type), the encoded limit at 8,079 and 8,080 characters and with doubled
quotes, a table header, a protected sheet, and a formula's spill taken
away. A UI test edits a Python cell's code with F2 and Enter, commits it
unchanged, and types over it; another clears a Python cell by deleting
all its code, keeps code of spaces, and undoes the clearing.
2026-10-26 10:18:38 -04:00