Private
Public Access
0
0
Commit Graph

4 Commits

Author SHA1 Message Date
Conductor be5dffa4f0 fix(md_renderer_py): inline code uses text_wrapped not small_button (fix ID conflict)
ROOT CAUSE: imgui.small_button(text) uses the text as the widget ID.
When the same inline code text appears multiple times in a rendered
markdown (e.g., the same function name in a table), imgui triggers
'3 visible items with conflicting ID' warning.

The C++ imgui-md SPAN_CODE callback is empty (renders as plain text).
Match that behavior: use text_wrapped with a slightly dimmed color
to indicate code spans. No widget ID, no conflicts.

ALSO: Added token cache to avoid re-parsing markdown every frame.
Each markdown-it-py parse is ~1ms; for static content re-rendered
every frame during scroll, the cache is the difference between smooth
and choppy. Cache is bounded to 64 entries (LRU-ish clear when full).

TESTS:
- test_renderer_renders_inline_code_with_button -> renamed intent,
  now asserts text_wrapped is called and a dimmed color is pushed
- test_render_handles_inline_code -> same update
- 2 new tests: test_renderer_caches_parsed_tokens, test_renderer_cache_invalidates_on_text_change

43/43 markdown tests pass.
2026-06-03 23:17:13 -04:00
Conductor 2d1d37779f fix(md_renderer_py): use Style.color_(Col_.X) API for imgui-bundle 1.92.5
The imgui-bundle 1.92.5 API changed:
  OLD: imgui.get_style().colors[imgui.Col_.text]
  NEW: imgui.get_style().color_(imgui.Col_.text)

The Style object no longer has a 'colors' dict; it has a 'color_'
method that takes a Col_ enum and returns the ImVec4 color.

Updated all 9 call sites in md_renderer_py.py and the test mocks
in test_md_renderer_py.py, test_markdown_helper_bullets.py, and
test_markdown_render_robust.py.

42/42 tests pass.
2026-06-03 23:06:05 -04:00
Conductor 3117061be5 fix(md_renderer_py): remove push_font for headings (API mismatch)
The imgui_bundle imgui.push_font() signature is:
  push_font(font: ImFont | None, font_size_base_unscaled: float) -> None

We were calling it with one arg (the font). This crashed imgui at
runtime, leaving imscope in a broken state and cascading to
subsequent scope errors (Missing EndGroup, PopID too many times,
Size > 0).

Since we don't have a separate heading font configured, just skip
the font push for headings. Headings render at the default font size
and use a separator (for h1/h2) to look distinct. User can subclass
MarkdownRenderer and override _handle_heading_open to add a custom
font later.

REMOVED: _get_heading_font method (no longer needed)
2026-06-03 22:55:14 -04:00
Conductor fe618055ca feat(markdown): pure-Python port of imgui_md with overlap fix
ADD src/md_renderer_py.py: Full port of mekhontsev/imgui_md to pure Python.
  - Uses markdown-it-py (already a transitive dep) for AST parsing.
  - Walks the token tree, calling imgui primitives directly.
  - Mirrors the C++ API surface: MarkdownOptions, MarkdownCallbacks,
    MarkdownRenderer.render(), render_unindented().
  - Code blocks delegated via set_external_code_block_handler callback.
  - All other content (paragraphs, headings, lists, code, tables, hr,
    emphasis, strong, links, blockquotes) rendered natively.

ROOT CAUSE OF BULLET OVERLAP (now fixed at the source):
  imgui-md C++ BLOCK_P guards NewLine() behind 'if (!m_list_stack.empty())'
  (imgui_md.cpp line ~145). Inside lists, paragraph transitions don't
  advance the cursor Y. The Python port calls imgui.new_line() explicitly
  between paragraphs in a list item, eliminating the overlap.

ROOT CAUSE OF '*' BULLET Y-OVERLAP (now fixed at the source):
  imgui-md C++ BLOCK_LI for '*' delim calls ImGui::Bullet() without
  ImGui::SameLine() (imgui_md.cpp line ~95). The Python port calls
  imgui.bullet() + imgui.same_line() for all markers uniformly.

REMOVED in src/markdown_helper.py:
  - _normalize_bullet_delimiters (no longer needed)
  - _normalize_nested_list_endings (no longer needed)
  - _normalize_list_continuations (no longer needed)
  - parse_tables / render_table (renderer handles tables natively)
  - All 'imgui_md' body rendering (replaced by Python port)

TESTS:
  - tests/test_md_renderer_py.py (new): 16 unit tests for the Python port
    covering paragraphs, headings, lists, nested lists, emphasis, strong,
    code, links, tables, hr, unindented.
  - tests/test_markdown_helper_bullets.py (rewritten): 13 tests for the
    integration with the public MarkdownRenderer class.
  - tests/test_markdown_render_robust.py (updated): 2 tests verifying
    table content is routed through the new Python renderer (not imgui_md).
  - tests/test_markdown_table.py / _render.py / _columns.py / _wrapped.py:
    unchanged (test the standalone render_table which is still used by
    the new renderer as a fallback for any unhandled cases).

42/42 markdown tests pass. 1-space indentation. 1 C++ dependency
removed (imgui_md is no longer used at runtime).

NOT FIXED (known limitations of the new renderer):
  - Inline code rendering uses a tinted small_button (not monospace)
  - Heading fonts use the default font (no separate bold/large fonts)
  - Image rendering shows a placeholder text
  - These can be improved by subclassing MarkdownRenderer
2026-06-03 22:43:41 -04:00