Add support for dfrac and tfrac LaTeX commands

Add display-style (dfrac) and text-style (tfrac) fraction commands
  to SwiftMath's LaTeX parser. These commands force fractions to render
  in specific styles regardless of context.

  Implementation:
  - Add dfrac parsing to prepend displaystyle to numerator/denominator
  - Add tfrac parsing to prepend textstyle to numerator/denominator
  - Implement in both parser functions in MTMathListBuilder.swift

  Testing:
  - Add testDisplayStyleFraction() for dfrac validation
  - Add testTextStyleFraction() for tfrac validation
  - Add testDisplayAndTextStyleFractions() for complex expressions
  - All 180 tests pass on macOS and iOS simulator

  Documentation:
  - Update MISSING_FEATURES.md (7/12 features now implemented, 58%)
  - Update README.md feature list to include dfrac and tfrac

  Fixes issue where equations like y'=-\dfrac{2}{x^{3}} would fail to
  parse with "Invalid command dfrac" error. This was blocking the
  StepByStep feature preview rendering.
This commit is contained in:
Nicolas Guillot
2025-11-03 10:23:49 +01:00
parent 43faacf8de
commit d2df078dc9
4 changed files with 191 additions and 4 deletions

View File

@@ -702,6 +702,34 @@ public struct MTMathListBuilder {
frac.numerator = self.buildInternal(true)
frac.denominator = self.buildInternal(true)
return frac;
} else if command == "dfrac" {
// Display-style fraction command has 2 arguments
let frac = MTFraction()
let numerator = self.buildInternal(true)
let denominator = self.buildInternal(true)
// Prepend \displaystyle to force display mode rendering
let displayStyle = MTMathStyle(style: .display)
numerator?.insert(displayStyle, at: 0)
denominator?.insert(displayStyle, at: 0)
frac.numerator = numerator
frac.denominator = denominator
return frac;
} else if command == "tfrac" {
// Text-style fraction command has 2 arguments
let frac = MTFraction()
let numerator = self.buildInternal(true)
let denominator = self.buildInternal(true)
// Prepend \textstyle to force text mode rendering
let textStyle = MTMathStyle(style: .text)
numerator?.insert(textStyle, at: 0)
denominator?.insert(textStyle, at: 0)
frac.numerator = numerator
frac.denominator = denominator
return frac;
} else if command == "binom" {
// A binom command has 2 arguments
let frac = MTFraction(hasRule: false)
@@ -1048,6 +1076,34 @@ public struct MTMathListBuilder {
frac.numerator = self.buildInternal(true)
frac.denominator = self.buildInternal(true)
return frac
} else if command == "dfrac" {
// Display-style fraction command has 2 arguments
let frac = MTFraction()
let numerator = self.buildInternal(true)
let denominator = self.buildInternal(true)
// Prepend \displaystyle to force display mode rendering
let displayStyle = MTMathStyle(style: .display)
numerator?.insert(displayStyle, at: 0)
denominator?.insert(displayStyle, at: 0)
frac.numerator = numerator
frac.denominator = denominator
return frac
} else if command == "tfrac" {
// Text-style fraction command has 2 arguments
let frac = MTFraction()
let numerator = self.buildInternal(true)
let denominator = self.buildInternal(true)
// Prepend \textstyle to force text mode rendering
let textStyle = MTMathStyle(style: .text)
numerator?.insert(textStyle, at: 0)
denominator?.insert(textStyle, at: 0)
frac.numerator = numerator
frac.denominator = denominator
return frac
} else if command == "binom" {
let frac = MTFraction(hasRule: false)
frac.numerator = self.buildInternal(true)