feat(view): fit a stated box's label to it, draw symbol kinds as their notation, and leave migration bookkeeping undrawn - #560
Merged
Conversation
A view's DiagramLayout annotations and its render members describe the picture, not the model; the shared member walk now skips them so every graphical form omits them, while ordinary metadata usages stay shown. Co-Authored-By: jason.han <hanhuijun@gmail.com>
… owner Co-Authored-By: jason.han <hanhuijun@gmail.com>
…heir notation A node a Layout sizes keeps its box: the head word-wraps at the width and shrinks from 14pt to 8pt until it fits the height, the keyword and detail lines follow only while height remains, and a head too long at 8pt is cut and ellipsized. Decision, merge and choice nodes in stated boxes are drawn as diamonds, forks and joins as filled bars, initial nodes as the filled dot, final nodes and terminate actions as the double ring, and ports as their square, with no text inside; a name is set beside the symbol unless the node marks it as synthesized. A terminate action usage is kinded as one, so the notation's final node is recognised. Co-Authored-By: jason.han <hanhuijun@gmail.com>
… and the bookkeeping left undrawn Co-Authored-By: jason.han <hanhuijun@gmail.com>
…he dot or ring Co-Authored-By: jason.han <hanhuijun@gmail.com>
Co-Authored-By: jason.han <hanhuijun@gmail.com>
…nclosing box before the boxes in it Co-Authored-By: jason.han <hanhuijun@gmail.com>
…ments unnamed A bundled MigrationMetadata::SynthesizedName metadata def, written once per body as an about list over the names the migration made up; the semantic model reads it (Model.NameSynthesized), the view IR carries it on nodes, and the graphical writers draw such an element as its source did: a bare control symbol, an edge without a label, a typed node as ': Type'. An action's language-given start and done are treated the same way. Re-indexed twins of one declaration share the about annotations the declaration gathered. Co-Authored-By: jason.han <hanhuijun@gmail.com>
…baseline Co-Authored-By: jason.han <hanhuijun@gmail.com>
…ing one Co-Authored-By: jason.han <hanhuijun@gmail.com>
Co-Authored-By: jason.han <hanhuijun@gmail.com>
Co-Authored-By: jason.han <hanhuijun@gmail.com>
Contributor
Author
|
I'll fix CI failures and address comments from users with write access. I'll skip comments containing "(aside)".
|
…me a member below its resolved owner A stated box that encloses other stated boxes fits its title to the strip above the topmost of them and sets it there (labelloc=t), so a container's title is not covered by its members, which keep their stated geometry. A box the Layout only places is sized to its label and does not move the title. A node now carries the qualified names its typings resolve to (Node.Typings, from Model.DeclaredTypes), so a member drawn inside a usage whose written type differs from the type's canonical name is still headed below it. Co-Authored-By: jason.han <hanhuijun@gmail.com>
…et them in a strip below it on request A DOT drawing that positions some nodes left the others to neato, which set them over the placed boxes. They are now omitted with the edges at them, under a notice, so a migrated diagram shows what its source showed. The new -render-unplaced strip (Options.Unplaced) packs them in rows below the canvas or the positioned extent instead, on -render, -render-all, -render-document and -render-documents alike. Every drawn node is pinned, so the layout header never names plain neato. Co-Authored-By: jason.han <hanhuijun@gmail.com>
6 tasks
…-label-fitting The bundled library snapshot is regenerated with both AnalysisRecords and MigrationMetadata, the migration goldens the merge brought in gain their SynthesizedName markers, the self-model counts the twelfth library extension, and the pilot differential baseline re-records the examples digest; every verdict in it is unchanged. Co-Authored-By: jason.han <hanhuijun@gmail.com>
Co-Authored-By: jason.han <hanhuijun@gmail.com>
…abel Graphviz pads a node's label by its default margin of 0.11 by 0.055 in, so a head fitted to the full stated width could still be drawn past the box's border. A stated box that carries a label now sets margin=0, so the fit and the drawing agree; a head filling the width keeps its size, one a point over it shrinks. Co-Authored-By: jason.han <hanhuijun@gmail.com>
…rk every synthesized declaration name A port with no given name but a type drew nothing beside its square; the type is now set as its xlabel like a given name. Anonymous parameters, port payloads, generated subjects, stakeholders, includes and instance slots are declared under a synthesized name that the SynthesizedName marker did not cover; they are now marked, and an empty name is never marked. Co-Authored-By: jason.han <hanhuijun@gmail.com>
Contributor
Author
There was a problem hiding this comment.
Devin Review found 1 new potential issue.
2 flags not posted on this PR by your GitHub settings — view them in Devin Review. (Configure)
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.
What and why
A SysML v1 migration with
-layoutreproduces Cameo's box geometry exactly (pos,width/height,fixedsize=true), but the DOT writer put its own label —name : Typeat 14 pt bold, a«kind»line, the detail lines, unwrapped — into boxes Cameo had sized for the name alone at about 11 px. Over the TMT model that overflowed 2,012 of 2,927 stated boxes in width and 1,631 in height, control nodes and ports (24×12 diamonds, 120×6 bars, 15×15 squares) carried labels they could never hold, nested members repeated their owner's qualified path, and tree views over packages of migrated views filled withmetadata/x/y/width/height/asTreeDiagramnodes. Four changes, one PR since they all reshape the same labels; the stated geometry is untouched throughout.1. The label is fitted to a stated box, never the box to the label (
dotFittedLabel,dotFitHead,dotWrapininternal/ir/view/dot.go). WhenGeometry.HasSize, the head is word-wrapped at the box width and drawn at the largest whole point size from 14 down to 8 at which the wrapped lines stack inside the height, preferring a size at which every word stays whole and breaking a word only when no size keeps it whole; the keyword line (at 10/14 of the head size) and each detail line follow only while height remains; a head that does not fit even at 8 pt is cut to the lines that fit and ellipsized. The estimator is the one the unsized boxes are already fitted with (dotGlyphEm,dotBoldGlyphEm,dotLineEm) — nothing Cameo-specific. Nodes without a stated size are unchanged. A stated box that holds other stated boxes — a part drawn round its members, a definition over its compartment rows — sets its title in the strip above the topmost of them and fits it to that strip (headroom,labelloc=t), so the title reads as the frame's header instead of being covered by the members, which keep their stated geometry; a box the Layout only places is sized to its own label and does not move a title.2. Symbol kinds in a stated box are drawn as their notation, with no inner text (
dotSymbolAttributes). decision/merge/choice →shape=diamond; fork/join → the filled bar; initial/junction → filled circle; final/terminate → filleddoublecircle; ports → the small square. The name goes beside the symbol asxlabel, and is left out when it is one the model did not give.How the renderer knows a name was made up. The migrator keeps that fact in memory only, so it now writes it into the model: a new bundled library
MigrationMetadata(internal/workspace/libs/stdlib/OpenSysML Libraries/MigrationMetadata.sysml) declaresmetadata def SynthesizedName, and the migrator emits, once per body that contains any,metadata MigrationMetadata::SynthesizedName about decide2, fork, 'start to call';($::MigrationMetadata::…when the model shadows the package; targets quoted by the ordinary name-writing rule).semantics.Model.NameSynthesizedreads it by resolved type, not by name text, and combines direct andaboutannotations — with a declaration-keyed fallback so a symbol re-indexed after an edit still finds its annotations (semantics/annotations.go). The view IR carries it asNode.NameSynthesized(also the language's ownstart/done, which no body named) and the LSP's render payload exposes it. Edges:edgeLabelno longer promotes a synthesized edge name to a label, while a trigger, guard, effect, flow payload or binding text is kept. Nothing pattern-matches names likedecide2orfork.3. A member drawn under its owner is headed by its name below that owner (
labellerinlabel.go).'K-Mirror Offset'::'interpolation Error' : 'Interpolation Error'inside the'K-Mirror Offset'box reads'interpolation Error' : 'Interpolation Error', at every nesting depth and for an exposed element whose owner is drawn in the same rendering, typed owners and qualified type references included. A node carries the qualified names its typings resolve to (Node.Typings, fromModel.DeclaredTypes), so a member drawn inside a usage whose written type differs from the type's canonical name ('summit Installation' : 'Summit Installation'holdingcomputer : Control) is still headed below it. Rendering-time only, in the graphical forms' heads; text, JSON, Mermaid text and the LSP keep the qualified name.4. A view's layout annotations and
rendermembers are not diagram content (tree.go, the member walk every rendering kind shares).DiagramLayout::Canvas/Layout/Routeannotations — wherever owned, recognised by resolved type (semantics/layout.go) — and therendermembers a view holds are left out of the walk. Every other metadata usage, and a rendering usage outside a view, is drawn as before (bookkeeping_test.gopins both).Also fixed on the way, because the marker exposed it: lowering a
state … parallelbody refused ametadatamember as unsupported content, so the migrated TCS state machine (whose parallel state now carries the marker) rendered empty.parallelOwnedMemberininternal/ir/lower/state_graph.gonow treats a metadata usage as the state's own member, like an attribute or a port, so only the substates are regions.Pinned expectations that changed, and why
internal/ir/view/dot_test.go—TestDOTWritesTheGeometry:pump : Pumpin a stated 100×50 box is nowpump<br/>: Pump(eleven bold 14 pt glyphs overrun 100 pt, so the head wraps; the box is unchanged).TestDOTLabelShape: a name-less typed node reads: Pumpwith its keyword instead of the bare kind word; new rows for a synthesized name (: doTracking+ keyword) and a synthesized untyped name (kind word). The pinned pseudo-statedonein a stated 10×10 box is now the double ring withxlabel="done"rather than a label it could not hold.xlabeljoined the attributes whose values must be quoted.internal/ir/view/plantuml_test.go— an action'sstart/doneare the language's names, not the body's, so they head as their kind (**initial**,**final**) in PlantUML as they now do in DOT.tests/migrate/layout_test.go—TestGoldenControlNodeLayout: the fork in a stated 120×6 box is the bare bar, the decision a diamond withxlabel="check"(v1-given), the initial/final dots and rings, and the migrator-named'start to fork'edge carries no label; the test also asserts those made-up names are absent.TestMigratedRoutesRenderPinned:'start to gain','engine to wheel','engine to wheel 2'and'mass = limit'were migrator-made names — the edges now read as their kind (connection,binding) or nothing, whilefinish,drive,result to valueandaccept Resume(source-given or real edge text) are unchanged.internal/translate/migrate/diagrams_internal_test.go,writer_test.go,tests/migrate/testdata/xmi/*.golden.sysml— each body that names something the source left unnamed gains onemetadata MigrationMetadata::SynthesizedName about …;line. That is the only change to emitted text.README.md,docs/internals/testing.md,docs/reference/grammar/README.md,examples/self-model/*.sysml— the bundled library count moved from 104 to 105 files (make docs-counts).docs/project/pilot-differential-baseline.json— examples digest re-recorded (go run -C tools ./cmd/pilot-diff -update); only the digest and date moved.Specification basis
SysML v2 §7.24 Views and Viewpoints, §10.2: the rendering is tool-defined;
rendermembers and the annotations that place a view are about the picture, not the exposed set. Metadata usages on a parallel state are ordinary owned members (SysML v2 §7.20 State-Based Behavior: a parallel state's regions are its nested states). The compliance rows for the DOT form indocs/project/spec-compliance.mdare extended; no row moves status.How it was verified
Unit tests:
internal/ir/view/dot_fit_test.go(fit at 14 pt, shrink to 8 pt, keyword/detail only while height remains, a compartment row's one line, a word broken only when no size keeps it whole, the ellipsis at the floor, each symbol kind's shape andxlabel, an unsized node unchanged),label_test.go(owner-relative heads at every depth, typed owners, qualified types, the text form untouched),bookkeeping_test.go(layout annotations andrendermembers left out; user metadata still drawn;NameSynthesizedread semantically from the marker),internal/ir/lower/state_graph_nested_test.go(a metadata usage in a parallel body is not a region),internal/translate/migrate/writer_test.go(one marker per body, attached to the right body when bodies nest, quoting),internal/syntax/source/name_test.go,tests/migrate/layout_test.go.Gates, all green:
gofmt -l .(empty),go vet ./...,go build ./...,make testandmake lint,go test ./...withOPENSYSML_REQUIRE_TRAINING_CORPUS=1 OPENSYSML_REQUIRE_PILOT_CORPORA=1 OPENSYSML_REQUIRE_PILOT_LIBRARY_XMI=1 OPENSYSML_REQUIRE_PSSM_SUITE=1after the four download scripts (training corpus, pilot corpora, pilot library XMI, PSSM suite, RDF round-trip included),python3 scripts/changelog.py check,scripts/check-doc-ids.py,scripts/check-doc-links.py,scripts/check-doc-figures.py,go run -C tools ./cmd/doc-counts -check,go test -C tools ./referee/diff.TMT before/after
Same source and MTIP export,
sysml TMT-2024x.mdzip -convert sysml -layout TMT_mtip.xml, then-render-all … -render-form dot(2,641 DOT views on both branches, identical render diagnostics, the same 1,063 views empty on both) and every DOT rendered with the engine its// layout:header names.size too small for labelwarningsThe 67 remaining warnings are the estimator's: 0.66 em per bold glyph is low for all-capital names in Helvetica bold (
Commandas a 13 pt port def head measures 73 px in a 64 px box;DETECTOR_EXPOSURE(CONTINUOUS)), and 15 constraint parameters drawn as 15×15 pins whose owner is not in the view (D…). Widening the estimate would move the unsized boxes too, so it is left alone. The 298 ellipsized heads are mostly 15×15 pins and compartment rows Cameo also clipped (analysisDriver : 'Analysis…in a 155×14 row).The migration report and the results sidecar are byte-identical to develop's. The emitted
.sysmldiffers only by themetadata MigrationMetadata::SynthesizedName about …;lines (1,757 in TMT, now that anonymous parameters, generated includes, stakeholders and instance slots are marked too), one per body that names something the source did not.Shear plate
SendAckactivity — before / after:'K-Mirror Offset Error Budget - Details'tree — before / after (the two blobs of layout metadata are gone, members read below their owner, a definition's title sits above its compartment rows; the members the Cameo diagram did not draw have noLayout, soneatostill places them where it likes):TCS state machine — after:
'APS Physical'IBD — after (each part's title in the strip above its members, ports as squares with their names beside them, part labels fitted):Checklist
make testandmake lintpass locallychanges/unreleased/<slug>.<section>.md, not as an edit toCHANGELOG.mdmake docs-countsrun if a gate count moved (compliance rows need nothing: the census is counted at docs build)F4,K5) in the body, docs, or changelog