Flowchart Module Refactoring Plan

February 17, 2026 · View on GitHub

Status: COMPLETED (Feb 2026, Task 17). See Flowchart Modular Refactor for the implementation results.

Overview

This document provides a comprehensive analysis of src/markdown/mermaid/flowchart.rs (~3,500 lines) and proposes a detailed refactoring strategy to split it into focused, maintainable modules.

Goal: Improve maintainability, reduce cognitive load, enable parallel development, and preserve all recent bug fixes (Tasks 43, 44, 46, 57).

Current Structure Analysis

File Statistics

SectionLines% of FileDescription
AST Types1-1354%Core data structures
Parser136-103426%Parsing logic
Layout Engine1036-249742%Sugiyama algorithm, subgraph layout
Renderer2499-349628%Drawing functions
Total3,496100%

Section Breakdown

1. AST Types (Lines 1-135, ~135 lines)

Core data structures representing the flowchart model:

TypePurposeDependencies
FlowDirectionEnum: TopDown, BottomUp, LeftRight, RightLeftNone
NodeShapeEnum: Rectangle, RoundRect, Stadium, Diamond, etc.None
FlowNodeStruct: id, label, shapeNodeShape
EdgeStyleEnum: Solid, Dotted, ThickNone
ArrowHeadEnum: Arrow, Circle, Cross, NoneNone
FlowEdgeStruct: from, to, label, style, arrowsEdgeStyle, ArrowHead
FlowSubgraphStruct: id, title, node_ids, childrenFlowDirection
NodeStyleStruct: fill, stroke, stroke_widthegui::Color32
FlowchartMain container: nodes, edges, subgraphs, classesAll above

Issues:

  • egui::Color32 import creates renderer dependency in types
  • NodeStyle is styling concern mixed with AST

2. Parser (Lines 136-1034, ~900 lines)

Parsing functions for converting Mermaid source text to AST:

FunctionLines ~PurposeRecent Fixes
parse_flowchart141-334Main entry point-
SubgraphBuilder338-344Helper struct for parsing-
parse_subgraph_header348-402Extract subgraph id/title-
parse_direction404-421Parse TD/LR/BT/RLTask 43 (semicolon)
parse_class_def425-475Parse classDef directive-
parse_class_assignment479-511Parse class assignments-
parse_css_color515-550Parse hex colors-
parse_stroke_width554-558Parse stroke-width values-
ARROW_PATTERNS562-577Edge pattern definitionsTask 44
find_arrow_pattern581-599Find arrow in textTask 44
parse_edge_label603-617Extract pipe-style labels-
extract_dash_label631-686Extract dash-style labelsTask 44
strip_trailing_semicolon688-691Remove trailing ;Task 43
split_by_ampersand695-740Handle A & B syntaxTask 43
parse_edge_line_full745-850Main edge parserTask 43, 44
parse_node_from_text852-1009Parse node shapesTask 54 (asymmetric)
extract_id1012-1021Extract node ID-
clean_label1025-1030Clean HTML in labels-
parse_node_definition1032-1034Wrapper for FlowNode-

Issues:

  • Large function count makes navigation difficult
  • parse_edge_line_full is complex (~100 lines) with multiple concerns
  • Helper functions scattered throughout

3. Layout Engine (Lines 1036-2497, ~1,460 lines)

The largest section, implementing Sugiyama-style layered graph layout:

ComponentLines ~PurposeRecent Fixes
NodeLayout1042-1045Position and size for a node-
SubgraphLayout1048-1056Subgraph bounding box-
FlowchartLayout1059-1066Complete layout result-
layout_flowchart1079-1113Main entry point-
compute_subgraph_layouts1120-1284Compute subgraph boundsTask 57
FlowLayoutConfig1287-1301Layout parameters-
FlowGraph1304-1422Internal graph representation-
SugiyamaLayout1425-2497Core layout algorithmTask 46
SubgraphInternalLayout1437-1445Internal subgraph positions-
SubgraphLayoutEngine1448-1833Subgraph content layoutTask 56

SugiyamaLayout Methods:

MethodLines ~PurposeRecent Fixes
new1836-1850Constructor-
compute1854-1880Main algorithm-
layout_subgraphs_inside_out1884-1909Subgraph ordering-
get_subgraph_processing_order1912-1944Topological sort-
detect_cycles_and_mark_back_edges1948-1961Cycle detection-
dfs_find_back_edges1963-1983DFS helper-
assign_layers1991-2058Layer assignment-
cluster_subgraph_layers2066-2117Group subgraph nodes-
compute_subgraph_relative_layers2121-2186Relative layering-
ensure_layer_constraints2190-2213Constraint propagation-
build_layers2216-2241Build layer structure-
get_min_incoming_edge_position2245-2257Edge position helper-
reduce_crossings2261-2275Barycenter heuristic-
order_layer_by_barycenter2279-2371Single layer ordering-
assign_coordinates_with_subgraphs2378-2496Final positioningTask 46

Issues:

  • SugiyamaLayout is monolithic (~660 lines)
  • SubgraphLayoutEngine is tightly coupled
  • Direction handling duplicated in multiple places

4. Renderer (Lines 2499-3496, ~1,000 lines)

Drawing functions for rendering the flowchart:

FunctionLines ~Purpose
FlowchartColors struct2505-2556Color configuration
EdgeLabelInfo struct2559-2563Pre-computed label sizes
render_flowchart2565-2675Main render entry point
compute_subgraph_depths2679-2705Calculate nesting depth
draw_subgraph2707-2743Draw subgraph box/title
draw_node2745-2901Draw node shapes
draw_edge2903-3222Draw edges with routing
draw_dashed_line3224-3243Helper for dotted edges
bezier_point3246-3257Bezier math
draw_bezier_curve3260-3277Draw curved edges
draw_arrow_head3279-3325Draw arrow heads
find_node_subgraph3329-3341Find containing subgraph
line_rect_intersection3345-3408Intersection math
SubgraphCrossingInfo3411-3417Edge crossing data
get_subgraph_crossing_info3421-3495Compute boundary crossings

Issues:

  • draw_edge is very complex (~320 lines)
  • Geometry helpers mixed with rendering
  • Color definitions embedded in renderer

Proposed Module Structure

src/markdown/mermaid/flowchart/
├── mod.rs              # Re-exports, public API (~80 lines)
├── types.rs            # AST types, enums (~150 lines)
├── parser.rs           # All parsing functions (~900 lines)
├── layout/
│   ├── mod.rs          # Layout entry point (~100 lines)
│   ├── graph.rs        # FlowGraph, adjacency (~200 lines)
│   ├── sugiyama.rs     # SugiyamaLayout (~500 lines)
│   ├── subgraph.rs     # SubgraphLayoutEngine (~400 lines)
│   └── config.rs       # FlowLayoutConfig (~50 lines)
├── render/
│   ├── mod.rs          # Render entry point (~100 lines)
│   ├── colors.rs       # FlowchartColors (~70 lines)
│   ├── nodes.rs        # draw_node (~200 lines)
│   ├── edges.rs        # draw_edge, arrows (~400 lines)
│   └── subgraphs.rs    # draw_subgraph (~100 lines)
└── utils.rs            # Shared utilities (~100 lines)

Module Responsibilities

mod.rs (~80 lines)

  • Re-export public API
  • Backward compatibility aliases
pub use types::*;
pub use parser::parse_flowchart;
pub use layout::layout_flowchart;
pub use render::{render_flowchart, FlowchartColors};

// For tests and internal use
pub(crate) use parser::{parse_direction, parse_edge_line_full, parse_node_from_text};

types.rs (~150 lines)

  • All AST types: FlowDirection, NodeShape, FlowNode, etc.
  • Layout result types: NodeLayout, SubgraphLayout, FlowchartLayout
  • No dependencies on egui (use generic color type or Option<[u8; 4]>)
// types.rs
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum FlowDirection { ... }

#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum NodeShape { ... }

// Color can be converted to/from egui::Color32 in render module
#[derive(Debug, Clone, Default)]
pub struct NodeStyle {
    pub fill: Option<[u8; 4]>,    // RGBA
    pub stroke: Option<[u8; 4]>,
    pub stroke_width: Option<f32>,
}

parser.rs (~900 lines)

  • parse_flowchart() main entry point
  • All parsing helpers
  • Internal struct SubgraphBuilder

layout/mod.rs (~100 lines)

  • layout_flowchart() entry point
  • Coordinate compute_subgraph_layouts()
  • Re-export layout types

layout/graph.rs (~200 lines)

  • FlowGraph struct and implementation
  • Graph construction from flowchart
  • Adjacency list management

layout/sugiyama.rs (~500 lines)

  • SugiyamaLayout struct
  • Cycle detection
  • Layer assignment
  • Crossing reduction
  • Coordinate assignment

layout/subgraph.rs (~400 lines)

  • SubgraphLayoutEngine
  • SubgraphInternalLayout
  • Hierarchical subgraph positioning

layout/config.rs (~50 lines)

  • FlowLayoutConfig struct
  • Default configuration values

render/mod.rs (~100 lines)

  • render_flowchart() entry point
  • Pre-computation of edge labels
  • Drawing orchestration

render/colors.rs (~70 lines)

  • FlowchartColors struct
  • dark() and light() presets

render/nodes.rs (~200 lines)

  • draw_node() function
  • Shape drawing (rectangle, diamond, circle, etc.)

render/edges.rs (~400 lines)

  • draw_edge() function
  • draw_arrow_head()
  • draw_bezier_curve()
  • Subgraph crossing detection

render/subgraphs.rs (~100 lines)

  • draw_subgraph()
  • compute_subgraph_depths()

utils.rs (~100 lines)

  • draw_dashed_line()
  • bezier_point()
  • line_rect_intersection()
  • Geometry helpers

Refactoring Strategy

Approach: Parallel Development with _legacy Suffix

To minimize risk, use a parallel development approach:

  1. Create new module structure alongside existing file
  2. Copy and adapt code into new modules
  3. Run tests against both implementations
  4. Switch imports in mod.rs when ready
  5. Remove legacy file after verification

Phase 1: Extract Types (Low Risk)

Goal: Create flowchart/types.rs with all type definitions.

  1. Create src/markdown/mermaid/flowchart/ directory
  2. Create flowchart/types.rs with all enums and structs
  3. Create flowchart/mod.rs with re-exports
  4. Update imports in flowchart.rs to use new types
  5. Verify all tests pass

Migration Path:

// flowchart.rs (temporary)
mod types;
pub use types::*;
// ... rest of file unchanged

Phase 2: Extract Parser (Medium Risk)

Goal: Move all parsing functions to flowchart/parser.rs.

Critical: Preserve Task 43, 44 fixes:

  • strip_trailing_semicolon() - Task 43
  • split_by_ampersand() - Task 43
  • parse_edge_line_full() - Task 43, 44
  • extract_dash_label() - Task 44
  • ARROW_PATTERNS ordering - Task 44
  1. Create flowchart/parser.rs
  2. Move parsing functions (keep exact implementations)
  3. Update parse_flowchart() to use moved functions
  4. Run parsing tests specifically
  5. Verify edge cases from Tasks 43, 44

Test Cases to Verify:

// Task 43: Semicolon handling
assert_parse("graph TD;\n  A-->B;");
assert_parse("A-->B;");

// Task 43: Ampersand handling  
assert_parse("A & B --> C");
assert_parse("A --> B & C");

// Task 44: Edge parsing
assert_parse("A -->|Yes| B");
assert_parse("A-- label -->B");

Phase 3: Extract Layout (High Risk)

Goal: Create flowchart/layout/ module hierarchy.

Critical: Preserve Task 46, 57 fixes:

  • assign_coordinates_with_subgraphs() - Task 46 (direction handling)
  • compute_subgraph_layouts() - Task 57 (viewport clipping)
  1. Create layout module structure
  2. Extract FlowLayoutConfig to layout/config.rs
  3. Extract FlowGraph to layout/graph.rs
  4. Extract SubgraphLayoutEngine to layout/subgraph.rs
  5. Extract SugiyamaLayout to layout/sugiyama.rs
  6. Create layout/mod.rs with entry point

Dependency Order:

config.rs (no deps)

graph.rs (depends on config, types)

subgraph.rs (depends on graph, config)

sugiyama.rs (depends on all above)

mod.rs (orchestrates)

Test Cases to Verify:

// Task 46: Direction handling
assert_layout_lr("flowchart LR\n  A --> B");
assert_layout_rl("flowchart RL\n  A --> B");
assert_layout_bt("flowchart BT\n  A --> B");

// Task 57: Viewport clipping
assert_no_negative_positions(layout);
assert_subgraph_contains_nodes(layout);

Phase 4: Extract Renderer (Medium Risk)

Goal: Create flowchart/render/ module hierarchy.

  1. Create render module structure
  2. Extract FlowchartColors to render/colors.rs
  3. Extract draw_node() to render/nodes.rs
  4. Extract draw_edge() and helpers to render/edges.rs
  5. Extract draw_subgraph() to render/subgraphs.rs
  6. Move utility functions to utils.rs

Phase 5: Integration and Cleanup

  1. Update src/markdown/mermaid/mod.rs imports
  2. Run full test suite
  3. Manual visual testing of all diagram types
  4. Remove flowchart.rs legacy file
  5. Update documentation

Risk Assessment

High-Risk Areas

AreaRiskMitigation
Task 46 (Direction)Layout breaks for LR/RL/BTKeep exact algorithm, comprehensive direction tests
Task 57 (Clipping)Content clipped in viewportTest nested subgraphs, verify positive coordinates
Edge parsingChained edges breakTest all ARROW_PATTERNS, verify edge declaration order

Recent Fix Locations

TaskFix LocationNew Module
43strip_trailing_semicolon, split_by_ampersand, parse_directionparser.rs
44ARROW_PATTERNS, find_arrow_pattern, extract_dash_label, parse_edge_line_fullparser.rs
46assign_coordinates_with_subgraphslayout/sugiyama.rs
54parse_node_from_text (asymmetric shape)parser.rs
55Title truncationlayout/mod.rs (compute_subgraph_layouts)
56Nested subgraph layoutlayout/subgraph.rs
57Viewport clippinglayout/mod.rs (coordinate shifting)

Public API Stability

Current Public Exports (from mod.rs)

// Must remain stable
pub use flowchart::{
    layout_flowchart,      // Main layout function
    parse_flowchart,       // Main parse function
    render_flowchart,      // Main render function
    FlowchartColors,       // Color configuration
    FlowDirection,         // Direction enum
    NodeShape,             // Shape enum
};

// Internal exports for tests
pub(crate) use flowchart::{
    parse_direction,       // Direction parsing
    parse_edge_line_full,  // Edge parsing
    parse_node_from_text,  // Node parsing
};

Proposed API (unchanged signatures)

// flowchart/mod.rs
pub fn parse_flowchart(source: &str) -> Result<Flowchart, String>;

pub fn layout_flowchart(
    flowchart: &Flowchart,
    available_width: f32,
    font_size: f32,
    text_measurer: &impl TextMeasurer,
) -> FlowchartLayout;

pub fn render_flowchart(
    ui: &mut Ui,
    flowchart: &Flowchart,
    layout: &FlowchartLayout,
    colors: &FlowchartColors,
    font_size: f32,
);

Implementation Checklist

Pre-Refactor

  • Create comprehensive test suite for all edge cases
  • Document current behavior for regression testing
  • Create backup branch

Phase 1: Types

  • Create flowchart/ directory
  • Create types.rs with all type definitions
  • Create mod.rs with re-exports
  • Verify compilation
  • Run all tests

Phase 2: Parser

  • Create parser.rs
  • Move all parsing functions
  • Verify Task 43 semicolon tests pass
  • Verify Task 44 edge parsing tests pass
  • Verify Task 54 asymmetric shape tests pass

Phase 3: Layout

  • Create layout/ directory structure
  • Extract config.rs
  • Extract graph.rs
  • Extract subgraph.rs
  • Extract sugiyama.rs
  • Create layout/mod.rs
  • Verify Task 46 direction tests pass
  • Verify Task 55 title tests pass
  • Verify Task 56 nested subgraph tests pass
  • Verify Task 57 viewport tests pass

Phase 4: Renderer

  • Create render/ directory structure
  • Extract colors.rs
  • Extract nodes.rs
  • Extract edges.rs
  • Extract subgraphs.rs
  • Create utils.rs
  • Visual testing

Phase 5: Cleanup

  • Update mermaid/mod.rs imports
  • Remove legacy flowchart.rs
  • Update documentation
  • Final test run

Success Criteria

  1. All existing tests pass without modification
  2. Visual parity with current rendering
  3. No performance regression in layout computation
  4. Clean module boundaries with minimal cross-dependencies
  5. Improved IDE navigation and code completion
  6. Preserved git history for bug tracking


Appendix: Function Reference

Parser Functions

FunctionSignatureUsed By
parse_flowchart(source: &str) -> Result<Flowchart, String>Public API
parse_direction(header: &str) -> FlowDirectionparse_flowchart, tests
parse_edge_line_full(line: &str) -> Option<(Vec<Node>, Vec<Edge>)>parse_flowchart, tests
parse_node_from_text(text: &str) -> Option<(String, String, NodeShape)>parse_edge_line_full, tests
parse_subgraph_header(line: &str, counter: &mut usize) -> (String, Option<String>)parse_flowchart
parse_class_def(line: &str) -> Option<(String, NodeStyle)>parse_flowchart
parse_class_assignment(line: &str, classes: &mut HashMap)parse_flowchart

Layout Functions

FunctionSignatureUsed By
layout_flowchart(flowchart, width, font_size, measurer) -> FlowchartLayoutPublic API
compute_subgraph_layouts(layout, flowchart, config, font_size, measurer)layout_flowchart
FlowGraph::from_flowchart(flowchart, font_size, measurer, config) -> FlowGraphSugiyamaLayout
SugiyamaLayout::compute(self) -> FlowchartLayoutlayout_flowchart

Render Functions

FunctionSignatureUsed By
render_flowchart(ui, flowchart, layout, colors, font_size)Public API
draw_node(painter, node, layout, offset, colors, font_size, style)render_flowchart
draw_edge(painter, edge, from, to, offset, colors, font_size, direction, ...)render_flowchart
draw_subgraph(painter, layout, offset, colors, font_size, depth)render_flowchart