Commit Graph

242 Commits

Author SHA1 Message Date
copilot-swe-agent[bot]
aba7f31f95 Add \operatorname{name} LaTeX command support
Agent-Logs-Url: https://github.com/wesleyel/swiftui-math/sessions/d2d346fe-819f-4ec5-8653-6582836c760d

Co-authored-by: wesleyel <48174882+wesleyel@users.noreply.github.com>
2026-04-06 13:55:45 +00:00
copilot-swe-agent[bot]
79b44fc96c Initial plan 2026-04-06 13:52:27 +00:00
Guille Gonzalez
cf7c70153b Update README.md 2026-01-12 09:19:42 +01:00
Guille Gonzalez
0b5c2cfaae Merge pull request #2 from gonzalezreal/prepare-for-release
Prepare for first release
2026-01-11 12:24:18 +01:00
Guille Gonzalez
c025214077 Add GitHub workflows 2026-01-11 12:11:31 +01:00
Guille Gonzalez
bb88ace8d6 Add issue template 2026-01-11 12:08:34 +01:00
Guille Gonzalez
9d3bb39914 Add CONTRIBUTING and CODE_OF_CONDUCT 2026-01-11 12:03:39 +01:00
Guille Gonzalez
45a1d276e0 Add SPI manifest 2026-01-11 11:52:18 +01:00
Guille Gonzalez
5fc1b7a19f Update README.md 2026-01-11 11:46:19 +01:00
Guille Gonzalez
1048aa5bac Merge pull request #1 from gonzalezreal/swiftui-refactoring
SwiftUI refactor
2026-01-11 08:55:02 +01:00
Guille Gonzalez
c90782cdd1 Add README and LICENSE 2026-01-11 08:42:50 +01:00
Guille Gonzalez
766150b954 Make multicolor convenience public 2026-01-11 07:43:06 +01:00
Guille Gonzalez
277f6420ba Remove original code 2026-01-11 06:55:41 +01:00
Guille Gonzalez
8d32feb1bd Add documentation 2026-01-11 06:53:55 +01:00
Guille Gonzalez
339f20a34b Add snapshot tests 2026-01-10 18:01:38 +01:00
Guille Gonzalez
00d93de457 Add FontMetricsTests 2026-01-10 17:45:16 +01:00
Guille Gonzalez
63f1c54f12 Handle empty font variant tables in FontMetrics 2026-01-10 06:14:44 +01:00
Guille Gonzalez
3d2294fe52 Make SPI typographicBounds method nonisolated 2026-01-09 16:33:57 +01:00
Guille Gonzalez
2c44010554 Add Font public initializer 2026-01-09 16:16:17 +01:00
Guille Gonzalez
baea9de415 Implement Math view 2026-01-05 14:19:42 +01:00
Guille Gonzalez
6e1a38ede7 Use CGColor and remove PlatformColor 2026-01-04 07:09:56 +01:00
Guille Gonzalez
fe6df90c4a Re-arrange source code and tests 2026-01-04 07:01:24 +01:00
Guille Gonzalez
0e865739f5 Fix text run display node 2026-01-04 06:42:53 +01:00
Guille Gonzalez
55abc5b2bd Implement DisplayNode drawing 2026-01-03 20:51:53 +01:00
Guille Gonzalez
a80b1ea3db Add Typesetter tests 2026-01-03 09:27:32 +01:00
Guille Gonzalez
e26d7d01b5 Add Typesetter 2026-01-03 08:11:38 +01:00
Guille Gonzalez
8e4db3cf0e Add display model 2026-01-03 07:45:34 +01:00
Guille Gonzalez
e9657c186e Add Parser tests 2026-01-02 19:36:05 +01:00
Guille Gonzalez
64b0090f3c Add AtomList tests 2026-01-02 18:41:22 +01:00
Guille Gonzalez
539942fffe Refactor Parser 2026-01-02 17:21:00 +01:00
Guille Gonzalez
e66eeb4564 Refactor model 2026-01-02 15:24:11 +01:00
Guille Gonzalez
fbfc1d0ecf Add font infrastructure 2026-01-01 12:13:22 +01:00
Guille Gonzalez
5e8e93b53e Add helpers 2025-12-31 12:59:11 +01:00
Guille Gonzalez
f805b3adf5 Clean slate 2025-12-31 12:40:11 +01:00
Guille Gonzalez
d056918e1e Update .gitignore 2025-12-31 09:22:26 +01:00
Guille Gonzalez
5774724d18 Rename package and address warnings 2025-12-30 14:45:54 +01:00
mgriebling
c49362fcf1 Merge pull request #55 from nguillot/multiline-improvements
Add multiline line breaking improvements for mathematical equations
2025-11-27 12:05:13 -05:00
Nicolas Guillot
9da5aba6b2 multiline fix with square root on second line 2025-11-21 15:49:27 +01:00
Nicolas Guillot
8ce6da114c code cleaning: remove print statement 2025-11-18 09:01:00 +01:00
Nicolas Guillot
90767b7953 Add performance optimization: skip line breaking when remaining content fits
Implement early-exit optimization to avoid expensive width calculations when
we can determine that all remaining content will definitely fit on the current line.
2025-11-18 08:41:26 +01:00
Nicolas Guillot
3aa6c6c98b Fix line width calculation for expressions with superscripts/subscripts
The typesetter was incorrectly measuring line width when expressions contained
  superscripts or subscripts (e.g., b²). After rendering a superscript, the line
  is split into multiple display segments, but the width checking code was only
  measuring the current segment, not the total visual line width.

  Key changes:
  - Use currentPosition.x to track actual horizontal position across all segments
  - Calculate visualLineWidth = currentPosition.x + currentSegmentWidth
  - Pass remainingWidth (maxWidth - currentPosition.x) to findBestBreakPoint
  - Apply fix to both interatom breaking and inline text breaking

  This fixes truncation issues where content like "Δ=b²-4ac avec a=1..." was
  being clipped instead of wrapped to a new line.

  Before: Each segment checked in isolation → segments appeared to fit individually
          but total visual width exceeded maxWidth → content truncated/clipped

  After:  Total visual width tracked correctly → line breaking triggered when
          actual visual width exceeds maxWidth → content wraps properly
2025-11-17 17:51:30 +01:00
Nicolas Guillot
43c69240bd Fix word breaking: prevent splitting words with accented characters
Fixed line breaking that would split words like "équivaut" into "é" on one
  line and "quivaut" on the next line, even though they're part of the same word.

  Root cause analysis (from debug logging):
  When text contains accented characters in decomposed form (e + combining
  accent), the system processes them as separate atoms:
    1. "é" is processed as an accent atom, composed, and added to currentLine
    2. "quivaut " is processed as the next ordinary atom
    3. Before adding "quivaut ", checkAndPerformInteratomLineBreak() is called
    4. This function sees that adding "quivaut " would exceed maxWidth
    5. It breaks and flushes the line with "é" at the end
    6. "quivaut " starts on a new line

  Result: "é" appears alone at the end of one line, "quivaut " on the next.

  The fix:
  Modified checkAndPerformInteratomLineBreak() in MTTypesetter.swift to detect
  when we're about to break in the middle of a word.
2025-11-17 10:45:32 +01:00
Nicolas Guillot
cc1a7b8023 Fix inline mode rendering for large operators and fractions
This commit addresses three issues with math rendering:

  1. Large operator limits positioning (continued from previous commit)
  Modified makeLargeOp() and addLimitsToDisplay() to show limits above/below
  in both display and text (inline) modes:
    - Changed: op.limits && style == .display
    - To: op.limits && (style == .display || style == .text)

  This enables operators like \lim, \sum, and \prod to show subscripts/
  superscripts above and below even in inline mode \(...\), not just in
  display mode \[...\].

  2. Fraction font size issue
  Fixed fractions appearing too small in inline mode. Previously, fractions
  used one style level smaller than their parent (standard LaTeX behavior):
    - Display mode → fractions use text style (acceptable)
    - Text mode →

  Root cause:
  Inline delimiters \(...\) insert \textstyle, forcing text mode. In text
  mode, fractionStyle() returned style.inc(), making numerator/denominator
  use script style (two levels smaller than display). This made fraction
  numbers tiny compared to surrounding text in expressions like:
    \(\frac{a}{b} = c\) - a, b were script-sized while c was text-sized

  Solution:
  Modified fractionStyle() to return the SAME style instead of incrementing:
    func fractionStyle() -> MTLineStyle {
        return style  // Was: return style.inc()
    }

  This keeps fraction numerators/denominators at the same font size as
  regular text, preventing them from becoming too small. Spacing and
  positioning (numeratorShiftUp, etc.) still vary by parent style.

  3. Non-regression fixes
  Updated test expectations to match new fraction sizing behavior
2025-11-17 10:12:45 +01:00
Nicolas Guillot
cb890fb787 Fix assert failures for unhandled atom types in inter-element spacing
Replace fatal asserts with explicit handling for all MTMathAtomType cases
  in getInterElementSpaceArrayIndexForType(). Previously, unhandled types
  (accent, number, variable, unaryOperator, underline, overline, boundary,
  space, style, table) would trigger assert failures and return Int.max,
  causing array out-of-bounds crashes.
2025-11-17 09:37:59 +01:00
Nicolas Guillot
b014be12b4 Add dynamic line height adjustment for multiline math display
Replace fixed fontSize × 1.5 spacing with adaptive height calculation based
  on actual line content (ascent + descent), providing better visual spacing
  for expressions with varying content heights.
2025-11-14 12:31:54 +01:00
Nicolas Guillot
ca0c3fbe07 Add break quality scoring
Implement aesthetic break point selection to prefer natural break locations
  (e.g., after operators) rather than arbitrary positions when line wrapping
  mathematical expressions.
2025-11-14 12:23:27 +01:00
Nicolas Guillot
4441528f46 Implement line breaking for scripted atoms and fix atom ordering 2025-11-14 10:45:51 +01:00
Nicolas Guillot
15269e87e5 Fix large operator positioning causing incorrect atom ordering
When rendering large operators (e.g., sum, integral) with scripts in text
  mode, the operator glyph was incorrectly positioned after its subscripts
  and superscripts instead of before them. This caused expressions like
  \sum_{i=1}^{n} i = \frac{n(n+1)}{2} to render with the equals sign
  appearing visually misplaced.

  Root cause:
  The line-breaking refactoring introduced double-positioning of large
  operators. makeLargeOp() internally sets the operator position, advances
  currentPosition.x, and adds script displays. However, the calling code
  then overwrote the position and advanced currentPosition.x again, causing:
  - Double-advancement leading to incorrect width calculations
  - Scripts positioned before the operator instead of after

  Solution:
  Save and restore typesetter state before/after line break dimension checks,
  then call makeLargeOp() once at the correct position after handling line
  breaks and inter-element spacing.
2025-11-14 10:32:10 +01:00
Nicolas Guillot
8cf87ef703 inline layout for all complex atom types
Extends the width-checking pattern from fractions/radicals to ALL remaining
  complex atom types, completing Priority 1 of the multiline implementation.

  Changes:
  - Large operators (∑, ∫, ∏): Now stay inline with height+width checking
    (breaks only if height > fontSize * 2.5 OR width exceeds constraint)
  - Delimiters (\left...\right): Stay inline with maxWidth propagation to
    inner content for proper nested wrapping
  - Colors (.color, .textcolor, .colorBox): All 3 types now stay inline with
    maxWidth propagation for proper nested wrapping
  - Matrices/tables: Small matrices can now stay inline with surrounding content
  - Width constraint propagation: All recursive createLineForMathList() calls
    now properly pass maxWidth parameter

Impact:
  Before: Complex atoms always forced line breaks, even when they fit
  After: ALL complex atoms intelligently stay inline when width permits

  Examples:
  - a + ∑ xᵢ + b → 1 line instead of 3
  - (a+b) + \left(\frac{c}{d}\right) + e → stays inline with wrapping
2025-11-14 09:53:14 +01:00
Nicolas Guillot
c5b737d9bb Line breaking for fractions and radicals fixes
Implement smart width-checking for complex mathematical displays to enable
  inline rendering when space permits, dramatically improving multiline layout.

  Changes:
  - Add shouldBreakBeforeDisplay() helper to check width before line breaks
  - Add performLineBreak() helper for clean line transitions
  - Modify fraction handling to stay inline when they fit within maxWidth
  - Modify radical handling to stay inline when they fit within maxWidth
  - Support radicals with degrees (cube roots, nth roots, etc.)
2025-11-13 15:45:35 +01:00