Skip to content

Commit 383ce8f

Browse files
authored
Merge pull request #14 from colinc86/develop
Develop
2 parents 82ff9a2 + a227b43 commit 383ce8f

18 files changed

+938
-223
lines changed

Package.resolved

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Package.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ let package = Package(
1515
targets: ["LaTeXSwiftUI"]),
1616
],
1717
dependencies: [
18-
.package(url: "https://github.com/colinc86/MathJaxSwift", from: "3.2.2"),
18+
.package(url: "https://github.com/colinc86/MathJaxSwift", from: "3.3.0"),
1919
.package(url: "https://github.com/exyte/SVGView", from: "1.0.4"),
2020
.package(url: "https://github.com/kean/Nuke", from: "12.1.0"),
2121
.package(url: "https://github.com/Kitura/swift-html-entities", from: "4.0.1")

README.md

Lines changed: 45 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
A SwiftUI view that renders LaTeX equations.
44

5-
![Swift Version](https://img.shields.io/badge/Swift-5.7-orange?logo=swift) ![iOS Version](https://img.shields.io/badge/iOS-16-informational) ![macOS Version](https://img.shields.io/badge/macOS-13-informational)
5+
[![](https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2Fcolinc86%2FLaTeXSwiftUI%2Fbadge%3Ftype%3Dswift-versions)](https://swiftpackageindex.com/colinc86/LaTeXSwiftUI) [![](https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2Fcolinc86%2FLaTeXSwiftUI%2Fbadge%3Ftype%3Dplatforms)](https://swiftpackageindex.com/colinc86/LaTeXSwiftUI)
66

77
<center><img src="./assets/images/device.png" width="362"></center>
88

@@ -20,7 +20,10 @@ A SwiftUI view that renders LaTeX equations.
2020
- [Equation Number Mode](#equation-number-mode)
2121
- [Equation Number Start](#equation-number-start)
2222
- [Equation Number Offset](#equation-number-offset)
23+
- [Format Equation Number](#format-equation-number)
2324
- [Unencode HTML](#🔗-unencode-html)
25+
- [Rendering Style](#🕶️-rendering-style)
26+
- [Animated](#🪩-animated)
2427
- [Caching](#🗄️-caching)
2528
- [Preloading](#🏃‍♀️-preloading)
2629

@@ -33,7 +36,7 @@ The view utilizes the [MathJaxSwift](https://www.github.com/colinc86/MathJaxSwif
3336
It will
3437
- render TeX and LaTeX equations (math-mode macros),
3538
- render the `\text{}` macro within equations,
36-
- attempt to render block equations as a Tex or LaTeX engine would,
39+
- attempt to render block equations as a TeX or LaTeX engine would,
3740
- and number block equations (if desired).
3841

3942
It won't
@@ -44,7 +47,7 @@ It won't
4447
Add the dependency to your package manifest file.
4548

4649
```swift
47-
.package(url: "https://github.com/colinc86/LaTeXSwiftUI", from: "1.1.0")
50+
.package(url: "https://github.com/colinc86/LaTeXSwiftUI", from: "1.2.0")
4851
```
4952

5053
## ⌨️ Usage
@@ -186,24 +189,26 @@ The default starting number is `1`, but if you need to start at a different valu
186189

187190
To change the left or right offset of the equation number, use the `equationNumberOffset` modifier.
188191

189-
```swift
190-
// Don't number block equations (default)
191-
LaTeX("$$a + b = c$$")
192-
.equationNumberMode(.none)
192+
##### Format Equation Number
193+
194+
You can set a closure on the view to do your own custom formatting. The `formatEquationNumber` modifier takes a closure that is passed the equation number and returns a string.
193195

194-
// Add left numbers and a leading offset
195-
LaTeX("$$d + e = f$$")
196-
.equationNumberMode(.left)
196+
```swift
197+
LaTeX("$$E = mc^2$$")
198+
.equationNumberMode(.right)
197199
.equationNumberOffset(10)
200+
.padding([.bottom])
198201

199-
// Add right numbers, a leading offset, and start at 2
200-
LaTeX("$$h + i = j$$ $$k + l = m$$")
202+
LaTeX("$$E = mc^2$$ $$E = mc^2$$")
201203
.equationNumberMode(.right)
204+
.equationNumberOffset(10)
202205
.equationNumberStart(2)
203-
.equationNumberOffset(20)
206+
.formatEquationNumber { n in
207+
return "~[\(n)]~"
208+
}
204209
```
205210

206-
> <img src="./assets/images/numbers.png" width="428" height="152">
211+
> <img src="./assets/images/numbers.png" width="433" height="153">
207212
208213
#### 🔗 Unencode HTML
209214

@@ -220,6 +225,30 @@ LaTeX("$x^2&lt;1$")
220225

221226
> <img src="./assets/images/unencoded.png" width="72.5" height="34">
222227
228+
#### 🕶️ Rendering Style
229+
230+
The view has four rendering styles. The `wait` style is the default style, and loads the view synchronously on the main queue. To get better performance and move SVG rendering off of the main queue, use any of the other three styles.
231+
232+
| Style | Asynchronous | Description |
233+
|:-----------|:-------------|:-------------------------------------------------------------------------|
234+
| `empty` | Yes | The view remains empty until its finished rendering. |
235+
| `original` | Yes | The view displays the input text until its finished rendering. |
236+
| `progress` | Yes | The view displays a progress view until its finished rendering. |
237+
| `wait` | No | *(default)* The view blocks the main queue until its finished rendering. |
238+
239+
240+
#### 🪩 Animated
241+
242+
The `animated` modifier applies to the view when using the asynchronous rendering styles `empty`, `original`, or `progress`.
243+
244+
```swift
245+
LaTeX(input)
246+
.renderingStyle(.original)
247+
.animated()
248+
```
249+
250+
> In the above example, the input text will be displayed until the SVGs have been rendered at which point the rendered views will animate in to view.
251+
223252
### 🗄️ Caching
224253

225254
`LaTeXSwiftUI` caches its SVG responses from MathJax and the images rendered as a result of the view's environment. If you want to control the cache, then you can access the static `dataCache` and `imageCache` properties.
@@ -240,8 +269,6 @@ LaTeX.imageCache.removeAll()
240269

241270
SVGs and images are rendered and cached on demand, but there may be situations where you want to preload the data so that there is minimal lag when the view appears.
242271

243-
SVGs and images are rendered as a result of the view's environment, so it is important to call the `preload` method last in the view's modifier chain if you use it.
244-
245272
```swift
246273
VStack {
247274
ForEach(expressions, id: \.self) { expression in
@@ -255,3 +282,5 @@ VStack {
255282
}
256283
}
257284
```
285+
286+
SVGs and images are rendered as a result of the view's environment, so it is important to call the `preload` method last in the view's modifier chain if you use it.

Sources/LaTeXSwiftUI/Extensions/EnvironmentValues+Extensions.swift

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,18 @@ private struct EquationNumberOffsetKey: EnvironmentKey {
6262
static let defaultValue: CGFloat = 0.0
6363
}
6464

65+
private struct FormatEquationNumberKey: EnvironmentKey {
66+
static let defaultValue: LaTeX.FormatEquationNumber = { "(\($0))" }
67+
}
68+
69+
private struct RenderingStyleKey: EnvironmentKey {
70+
static let defaultValue: LaTeX.RenderingStyle = .wait
71+
}
72+
73+
private struct AnimatedKey: EnvironmentKey {
74+
static let defaultValue: Bool = false
75+
}
76+
6577
extension EnvironmentValues {
6678

6779
/// The image rendering mode of this environment.
@@ -118,4 +130,22 @@ extension EnvironmentValues {
118130
set { self[EquationNumberOffsetKey.self] = newValue }
119131
}
120132

133+
/// The closure used to format equation number before displaying them.
134+
var formatEquationNumber: LaTeX.FormatEquationNumber {
135+
get { self[FormatEquationNumberKey.self] }
136+
set { self[FormatEquationNumberKey.self] = newValue }
137+
}
138+
139+
/// The rendering style of this environment.
140+
var renderingStyle: LaTeX.RenderingStyle {
141+
get { self[RenderingStyleKey.self] }
142+
set { self[RenderingStyleKey.self] = newValue }
143+
}
144+
145+
/// Whether or not rendering should be animated.
146+
var animated: Bool {
147+
get { self[AnimatedKey.self] }
148+
set { self[AnimatedKey.self] = newValue }
149+
}
150+
121151
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
//
2+
// Range+Extensions.swift
3+
// LaTeXSwiftUI
4+
//
5+
// Copyright (c) 2023 Colin Campbell
6+
//
7+
// Permission is hereby granted, free of charge, to any person obtaining a copy
8+
// of this software and associated documentation files (the "Software"), to
9+
// deal in the Software without restriction, including without limitation the
10+
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
11+
// sell copies of the Software, and to permit persons to whom the Software is
12+
// furnished to do so, subject to the following conditions:
13+
//
14+
// The above copyright notice and this permission notice shall be included in
15+
// all copies or substantial portions of the Software.
16+
//
17+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22+
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
23+
// IN THE SOFTWARE.
24+
//
25+
26+
import Foundation
27+
28+
extension Range<String.Index> {
29+
30+
/// Evaluates whether or not this range is a subrange of the given range.
31+
///
32+
/// - Parameter range: The range this range is a subset of.
33+
/// - Returns: Whether or not the receiver is a subset.
34+
func isSubrange(of range: Self) -> Bool {
35+
guard range.lowerBound != lowerBound || range.upperBound != upperBound else {
36+
return false
37+
}
38+
return range.lowerBound <= lowerBound && upperBound <= range.upperBound
39+
}
40+
41+
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
//
2+
// TeXInputProcessorOptions+Extensions.swift
3+
// LaTeXSwiftUI
4+
//
5+
// Copyright (c) 2023 Colin Campbell
6+
//
7+
// Permission is hereby granted, free of charge, to any person obtaining a copy
8+
// of this software and associated documentation files (the "Software"), to
9+
// deal in the Software without restriction, including without limitation the
10+
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
11+
// sell copies of the Software, and to permit persons to whom the Software is
12+
// furnished to do so, subject to the following conditions:
13+
//
14+
// The above copyright notice and this permission notice shall be included in
15+
// all copies or substantial portions of the Software.
16+
//
17+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22+
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
23+
// IN THE SOFTWARE.
24+
//
25+
26+
import Foundation
27+
import MathJaxSwift
28+
29+
extension TeXInputProcessorOptions {
30+
31+
/// Initializes a set of options with the correct properties set for rendering
32+
/// a `LaTeX` view.
33+
///
34+
/// - Parameters:
35+
/// - processEscapes: Whether or not escapes should be processed.
36+
/// - errorMode: The view's error mode.
37+
convenience init(processEscapes: Bool, errorMode: LaTeX.ErrorMode) {
38+
self.init()
39+
self.processEscapes = processEscapes
40+
41+
var packages = TeXInputProcessorOptions.Packages.all
42+
if errorMode != .rendered {
43+
if let noErrorsIndex = packages.firstIndex(of: TeXInputProcessorOptions.Packages.noerrors) {
44+
packages.remove(at: noErrorsIndex)
45+
}
46+
if let noUndefinedIndex = packages.firstIndex(of: TeXInputProcessorOptions.Packages.noundefined) {
47+
packages.remove(at: noUndefinedIndex)
48+
}
49+
}
50+
loadPackages = packages
51+
}
52+
53+
}

Sources/LaTeXSwiftUI/Extensions/View+Extensions.swift

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ public extension View {
4646
/// nothing.
4747
///
4848
/// - Returns: A preloaded view.
49-
@MainActor func preload() -> some View {
49+
func preload() -> some View {
5050
if let latex = self as? LaTeX {
5151
latex.preload()
5252
}
@@ -137,4 +137,29 @@ public extension View {
137137
environment(\.equationNumberOffset, offset)
138138
}
139139

140+
/// Sets a block that lets you format the equation number that will be
141+
/// displayed for named block equations.
142+
///
143+
/// - Parameter perform: The block that will format the equation number.
144+
/// - Returns: A view that formats its equation numbers.
145+
func formatEquationNumber(_ perform: @escaping LaTeX.FormatEquationNumber) -> some View {
146+
environment(\.formatEquationNumber, perform)
147+
}
148+
149+
/// Sets the view rendering style.
150+
///
151+
/// - Parameter style: The rendering style to use.
152+
/// - Returns: A view that renders its content.
153+
func renderingStyle(_ style: LaTeX.RenderingStyle) -> some View {
154+
environment(\.renderingStyle, style)
155+
}
156+
157+
/// Sets whether or not the view will animate its render state changes.
158+
///
159+
/// - Parameter animate: Whether animations are enabled.
160+
/// - Returns: A view that animates its rendering.
161+
func animated(_ animate: Bool = true) -> some View {
162+
environment(\.animated, animate)
163+
}
164+
140165
}

0 commit comments

Comments
 (0)