Repository navigation
Edit Logic Programmer expressions as text - #1767
Merged
Merged
Conversation
The expression panel gets Edit, Copy and Undo buttons. Edit turns the expression into text in the format of Integrated Scripting, which is parsed and type checked on the client while typing. Applying sends the resulting tree to the server once, as a single set action that the server validates, and makes the element of the new root operator active when it changed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MHtucHo4Qy2pTfBMgeE54y
Brings in the simplified expression panel. Edit, Copy, Undo, Apply and Cancel are now regular buttons in a row at the bottom of the panel, like the other buttons of the Logic Programmer, instead of drawn boxes in the title. The hint below the text box is gone with the other hints, and the type of the typed text is shown in the colors of its types. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MHtucHo4Qy2pTfBMgeE54y
The text box ends right above the footer of the panel, which shows the type of the typed text, or the parse error with its line and column. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MHtucHo4Qy2pTfBMgeE54y
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MHtucHo4Qy2pTfBMgeE54y
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MHtucHo4Qy2pTfBMgeE54y
Member
Author
|
Combined into #1766: its branch was fast-forwarded to include these commits and those of #1768, so this PR is closed. Generated by Claude Code |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stacked on #1766 (
feature/expression-cards), so this PR only shows the commits on top of it. It should be merged after that one, or retargeted tomaster-1.21-ltsonce that one is in.This is a first implementation of editing an expression in the Logic Programmer as text, and of copying it as text. The panel gets a row of regular buttons at the bottom:
(a: integer, b: integer) -> (a + b) * #5. While you type, the client parses and type checks the text and shows the inferred type in the colors of its types, or the first error with its line and column (Line 1, column 24: The text ends too early, a value is missing). Apply (or Ctrl+Enter) applies it and is disabled while the text does not parse; Cancel (or Esc) leaves without changes.Screenshots from the dev client: https://claude.ai/artifact/JKSFeHqKTEyB3H72wCD1tc
Design
Typing never waits on the server. Parsing, name resolution and type checking all run on the client, against the ref types the editor knows plus the cards in the player's inventory. Nothing is sent while typing. On Apply, the client applies the result locally and sends the tree once, as a new
setaction in the existingLogicProgrammerExpressionActionPacket. The server deserializes it with the existing limits (depth 64, 8 parameters, known operators and types) and also checksExpressionEditor.isEditable: the root is an operator, at most 1024 nodes, parameter names that the text form can read back, parameter types from the LP's list, and only operators that have a slot for each input. Anything else is ignored.Another root operator switches the element. Each LP element is one root operator, so if the text has another root (typing
(a + b) * 2while in>), the element of that operator becomes active, the same way loading a card does. The known ref types and the actual cards placed in slots are carried over first, since deactivating the old element forgets them.Text format. It reuses the naming from #1766, so it reads like Integrated Scripting.
length(s)for strings,length(l)for lists), and otherwise the global one (stringLength). Both are accepted when parsing.+ - * / % == != < <= > >= && ||with C precedence, prefix!, andc ? a : b.?is an empty slot, and(name)is an operator as a value, such as(+)or(stringLength).x -> ..., or(x: integer, y) -> ...with optional types.true/false,1,5L,1.5/1e3/2d/NaN/Infinity, and quoted strings with\" \\ \n \t \r \uXXXXescapes.@type{snbt}, so the printer is exact for every value, not only the common ones.#42refers to a card by ID.#limitor#"my label"refers to it by label, and only resolves when exactly one card has that label. Copy prints#labelonly in that case, and#idotherwise.ExpressionPrinter.printExactis the inverse ofExpressionParser.parse, and the tests check this both ways (see Testing).What changed
ExpressionParser(recursive descent with a small lexer, max 8192 characters) andExpressionParseException(position and translatable message). 28 error messages, all translatable.ExpressionPrinter.printExact,printLiteralandquote. The display form from Expression cards in the Logic Programmer, editable as text #1766 is unchanged.OperatorNames:getInfixOperator,getPrefixOperatorandgetScopedNameOperatorsfor parsing, andisRegisteredis now public.ExpressionEditor:ACTION_SETwithactionSet/readSetAction,isEditable(IOperator)(extracted from the existingopaction check) andisEditable(Expression),getParserContext,getKnownRefTypes. Renaming a parameter now also rejects names the text could not read back, such astrue,NaNor1x.OperatorLPElement:setExpression,getReferences/addReferences,getInventoryCardTypes.ContainerLogicProgrammerBase:applySetExpressionActionandgetOperatorElement(IOperator), plus client-side state for the text being edited and the undo. That state lives in the container, so it survives the panel being recreated.LabelsWorldStorage.getVariableIds(label).ContainerScreenLogicProgrammerBasealso forwards scrolling to the panel (dragging and releasing already are, for dragging parameters in Expression cards in the Logic Programmer, editable as text #1766), since CyclopsCore sub-GUIs only get clicks and keys and the text box needs them for scrolling and selecting.ButtonTextwidgets in the render pattern'sbuttonList, like the+button from Expression cards in the Logic Programmer, editable as text #1766, laid out right-aligned in a row at the bottom of the panel with the main action on the right. Copy shows "Copied" for a moment after a click.Things to decide on
#123for any ID. Evaluation still needs that variable in the same network, so I don't think this gives access to anything new, but it does relax the "refs only come from cards" rule I described in Expression cards in the Logic Programmer, editable as text #1766, so you should decide on it explicitly. Requiring the card in the inventory for every#idon the server would be easy to add, but it would also reject loading and re-applying a card whose referenced cards are elsewhere.MultiLineEditBox: black, full-size font, about 23 characters per line in the 138 px panel. It is readable, and long expressions wrap and scroll, but there is no syntax highlighting, completion or error underline yet (only line and column). These are the obvious next steps if you want to take this further.Testing
Unit tests: 973 pass, including 12 new in
TestExpressionParserand 2 new inTestExpressionEditor.Lsuffix on purpose makes two of them fail.Gametests: all 1053 pass, including the new
testLogicProgrammerSetExpressionAsText. It applies(#id + 3) * 2to a realContainerLogicProgrammerthat is on>, checks that Arithmetic Multiplication became active with that expression, and that a const root is ignored. It then writes the card and checks that a display panel shows 36.In the dev client (screenshots above, from the current version), I checked:
b ? 1 : "a"), cut off in the footer and complete on hoverInteger -> String -> String,Boolean -> Integer)enot closing it either#5card in its slot and rewrote the cardlength,concat) and string literalsThe vanilla box's own character counter overlapped the type, so it is turned off; the parser enforces the length limit instead. Reviewing the code also showed that the undo survived later visual edits, so Undo could throw them away. That is fixed, and the "visual edit hiding Undo" check covers it.
Not exercised in the client: Ctrl+Enter and paste. clientdevbridge sends modifier bits, but vanilla checks the physical key state with
Screen.hasControlDown(), so held Ctrl does not reach the GUI. I used the Apply button instead. Ctrl+Enter uses the samehasControlDown()check as vanilla's own shortcuts, and paste is vanillaMultiLineEditBoxbehavior.🤖 Generated with Claude Code
https://claude.ai/code/session_01MHtucHo4Qy2pTfBMgeE54y