[MTMathListBuilder][MTTypesetter] add \cfrac support

This commit is contained in:
Nicolas Guillot
2025-09-30 10:17:08 +02:00
parent 225948c725
commit 7c9766f825
3 changed files with 73 additions and 4 deletions

6
Sources/SwiftMath/MathRender/MTMathList.swift Executable file → Normal file
View File

@@ -328,6 +328,10 @@ public class MTFraction: MTMathAtom {
public var rightDelimiter = ""
public var numerator: MTMathList?
public var denominator: MTMathList?
// Continued fraction properties
public var isContinuedFraction: Bool = false
public var alignment: String = "c" // "l", "r", "c" for left, right, center
init(_ frac: MTFraction?) {
super.init(frac)
@@ -338,6 +342,8 @@ public class MTFraction: MTMathAtom {
self.hasRule = frac.hasRule
self.leftDelimiter = frac.leftDelimiter
self.rightDelimiter = frac.rightDelimiter
self.isContinuedFraction = frac.isContinuedFraction
self.alignment = frac.alignment
}
}

View File

@@ -508,7 +508,14 @@ public struct MTMathListBuilder {
}
if atom.type == .fraction {
if let frac = atom as? MTFraction {
if frac.hasRule {
if frac.isContinuedFraction {
// Generate \cfrac with optional alignment
if frac.alignment != "c" {
str += "\\cfrac[\(frac.alignment)]{\(mathListToString(frac.numerator!))}{\(mathListToString(frac.denominator!))}"
} else {
str += "\\cfrac{\(mathListToString(frac.numerator!))}{\(mathListToString(frac.denominator!))}"
}
} else if frac.hasRule {
str += "\\frac{\(mathListToString(frac.numerator!))}{\(mathListToString(frac.denominator!))}"
} else {
let command: String
@@ -685,6 +692,28 @@ public struct MTMathListBuilder {
} else if command == "frac" {
// A fraction command has 2 arguments
let frac = MTFraction()
frac.numerator = self.buildInternal(true)
frac.denominator = self.buildInternal(true)
return frac;
} else if command == "cfrac" {
// A continued fraction command with optional alignment and 2 arguments
let frac = MTFraction()
frac.isContinuedFraction = true
// Parse optional alignment parameter [l], [r], [c]
skipSpaces()
if hasCharacters && string[currentCharIndex] == "[" {
_ = getNextCharacter() // consume '['
let alignmentChar = getNextCharacter()
if alignmentChar == "l" || alignmentChar == "r" || alignmentChar == "c" {
frac.alignment = String(alignmentChar)
}
// Consume closing ']'
if hasCharacters && string[currentCharIndex] == "]" {
_ = getNextCharacter()
}
}
frac.numerator = self.buildInternal(true)
frac.denominator = self.buildInternal(true)
return frac;
@@ -981,6 +1010,27 @@ public struct MTMathListBuilder {
return accent
} else if command == "frac" {
let frac = MTFraction()
frac.numerator = self.buildInternal(true)
frac.denominator = self.buildInternal(true)
return frac
} else if command == "cfrac" {
let frac = MTFraction()
frac.isContinuedFraction = true
// Parse optional alignment parameter [l], [r], [c]
skipSpaces()
if hasCharacters && string[currentCharIndex] == "[" {
_ = getNextCharacter() // consume '['
let alignmentChar = getNextCharacter()
if alignmentChar == "l" || alignmentChar == "r" || alignmentChar == "c" {
frac.alignment = String(alignmentChar)
}
// Consume closing ']'
if hasCharacters && string[currentCharIndex] == "]" {
_ = getNextCharacter()
}
}
frac.numerator = self.buildInternal(true)
frac.denominator = self.buildInternal(true)
return frac

19
Sources/SwiftMath/MathRender/MTTypesetter.swift Executable file → Normal file
View File

@@ -990,9 +990,22 @@ class MTTypesetter {
func makeFraction(_ frac:MTFraction?) -> MTDisplay? {
// lay out the parts of the fraction
let fractionStyle = self.fractionStyle;
let numeratorDisplay = MTTypesetter.createLineForMathList(frac!.numerator, font:font, style:fractionStyle(), cramped:false)
let denominatorDisplay = MTTypesetter.createLineForMathList(frac!.denominator, font:font, style:fractionStyle(), cramped:true)
let numeratorStyle: MTLineStyle
let denominatorStyle: MTLineStyle
if frac!.isContinuedFraction {
// Continued fractions always use display style
numeratorStyle = .display
denominatorStyle = .display
} else {
// Regular fractions use adaptive style
let fractionStyle = self.fractionStyle;
numeratorStyle = fractionStyle()
denominatorStyle = fractionStyle()
}
let numeratorDisplay = MTTypesetter.createLineForMathList(frac!.numerator, font:font, style:numeratorStyle, cramped:false)
let denominatorDisplay = MTTypesetter.createLineForMathList(frac!.denominator, font:font, style:denominatorStyle, cramped:true)
// determine the location of the numerator
var numeratorShiftUp = self.numeratorShiftUp(frac!.hasRule)