Skip to content

Commit 82ff9a2

Browse files
authored
Merge pull request #12 from colinc86/v1.1
v1.1
2 parents f56f060 + 2600758 commit 82ff9a2

File tree

10 files changed

+366
-88
lines changed

10 files changed

+366
-88
lines changed

Package.resolved

Lines changed: 4 additions & 4 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
@@ -17,7 +17,7 @@ let package = Package(
1717
dependencies: [
1818
.package(url: "https://github.com/colinc86/MathJaxSwift", from: "3.2.2"),
1919
.package(url: "https://github.com/exyte/SVGView", from: "1.0.4"),
20-
.package(url: "https://github.com/kean/Nuke", from: "11.3.1"),
20+
.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")
2222
],
2323
targets: [

README.md

Lines changed: 78 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,50 @@
11
# LaTeXSwiftUI
22

3-
A SwiftUI view that renders LaTeX.
3+
A SwiftUI view that renders LaTeX equations.
44

55
![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)
66

7-
<center><img src="./assets/images/device.png" width="362" height="707"></center>
7+
<center><img src="./assets/images/device.png" width="362"></center>
88

99
## 📖 Contents
1010

11+
- [About](#ℹ️-about)
1112
- [Installation](#📦-installation)
1213
- [Usage](#⌨️-usage)
1314
- [Modifiers](#⚙️-modifiers)
1415
- [Parsing Mode](#🔤-parsing-mode)
1516
- [Image Rendering Mode](#🌄-image-rendering-mode)
1617
- [Error Mode](#🚨-error-mode)
1718
- [Block Rendering Mode](#🧱-block-rendering-mode)
19+
- [Numbered Block Equations](#🔢-numbered-block-equations)
20+
- [Equation Number Mode](#equation-number-mode)
21+
- [Equation Number Start](#equation-number-start)
22+
- [Equation Number Offset](#equation-number-offset)
1823
- [Unencode HTML](#🔗-unencode-html)
19-
- [TeX Options](#♾️-tex-options)
2024
- [Caching](#🗄️-caching)
2125
- [Preloading](#🏃‍♀️-preloading)
26+
27+
## ℹ️ About
28+
29+
`LaTexSwiftUI` is a package that exposes a view named `LaTeX` that can parse and render TeX and LaTeX equations which contain math-mode marcos.
30+
31+
The view utilizes the [MathJaxSwift](https://www.github.com/colinc86/MathJaxSwift) package to render equations with [MathJax](https://www.mathjax.org). Thus, the limitations of the view are heavily influenced by the [limitations](https://docs.mathjax.org/en/v2.7-latest/tex.html#differences) of MathJax.
32+
33+
It will
34+
- render TeX and LaTeX equations (math-mode macros),
35+
- render the `\text{}` macro within equations,
36+
- attempt to render block equations as a Tex or LaTeX engine would,
37+
- and number block equations (if desired).
38+
39+
It won't
40+
- render TeX and LaTeX documents (text-mode macros, with the exception of the rule above).
2241

2342
## 📦 Installation
2443

2544
Add the dependency to your package manifest file.
2645

2746
```swift
28-
.package(url: "https://github.com/colinc86/LaTeXSwiftUI", from: "1.0.4")
47+
.package(url: "https://github.com/colinc86/LaTeXSwiftUI", from: "1.1.0")
2948
```
3049

3150
## ⌨️ Usage
@@ -62,7 +81,7 @@ Along with supporting the built-in SwiftUI modifies, `LaTeXSwiftUI` defines more
6281

6382
#### 🔤 Parsing Mode
6483

65-
`LaTexSwiftUI` can parse and render equations (aside from the entire input string) defined with the following terminators.
84+
Text input can either be completely rendered, or the view can search for top-level equations delimited by the following terminators.
6685

6786
| Terminators |
6887
|-------------|
@@ -72,15 +91,20 @@ Along with supporting the built-in SwiftUI modifies, `LaTeXSwiftUI` defines more
7291
| `\begin{equation}...\end{equation}` |
7392
| `\begin{equation*}...\end{equation*}` |
7493

75-
Text input can either be completely rendered, or `LaTeXSwiftUI` can search for top-level equations. The default behavior is to only render equations with `onlyEquations`. Use the `parsingMode` modifier to change the default behavior.
94+
The default behavior is to only render equations with `onlyEquations`. Use the `parsingMode` modifier to change the default behavior.
7695

7796
```swift
97+
// Only parse equations (default)
98+
LaTeX("Euler's identity is $e^{i\\pi}+1=0$.")
99+
.font(.system(size: 18))
100+
.parsingMode(.onlyEquations)
101+
78102
// Parse the entire input
79-
LaTeX("e^{i\\pi}+1=0")
103+
LaTeX("\\text{Euler's identity is } e^{i\\pi}+1=0\\text{.}")
80104
.parsingMode(.all)
81105
```
82106

83-
> <img src="./assets/images/euler.png" width="75" height="19.5">
107+
> <img src="./assets/images/euler.png" width="293" height="80">
84108
85109
#### 🌄 Image Rendering Mode
86110

@@ -102,6 +126,8 @@ LaTeX("Hello, ${\\color{red} \\LaTeX}$!")
102126

103127
When an error occurs while parsing the input the view will display the original LaTeX. You can change this behavior by modifying the view's `errorMode`.
104128

129+
> Note: when the `rendered` mode is used, MathJax is instructed to load the `noerrors` and `noundefined` packages. In the other two modes, `original` and `error`, these packages are not loaded by MathJax and errors are either displayed in the view, or caught and replaced with the original text.
130+
105131
```swift
106132
// Display the original text instead of the equation
107133
LaTeX("$\\asdf$")
@@ -144,6 +170,41 @@ LaTeX("The quadratic formula is $$x=\\frac{-b\\pm\\sqrt{b^2-4ac}}{2a}$$ and it h
144170

145171
> <img src="./assets/images/blocks.png" width="430" height="350">
146172
173+
#### 🔢 Numbered Block Equations
174+
175+
The `LaTeX` view can do simple numbering of block equations with the `blockViews` block mode.
176+
177+
##### Equation Number Mode
178+
179+
Use the `equationNumberMode` modifier to change between `left`, `right` and `none`.
180+
181+
##### Equation Number Start
182+
183+
The default starting number is `1`, but if you need to start at a different value, you can specify it with the `equationNumberStart` modifier.
184+
185+
##### Equation Number Offset
186+
187+
To change the left or right offset of the equation number, use the `equationNumberOffset` modifier.
188+
189+
```swift
190+
// Don't number block equations (default)
191+
LaTeX("$$a + b = c$$")
192+
.equationNumberMode(.none)
193+
194+
// Add left numbers and a leading offset
195+
LaTeX("$$d + e = f$$")
196+
.equationNumberMode(.left)
197+
.equationNumberOffset(10)
198+
199+
// Add right numbers, a leading offset, and start at 2
200+
LaTeX("$$h + i = j$$ $$k + l = m$$")
201+
.equationNumberMode(.right)
202+
.equationNumberStart(2)
203+
.equationNumberOffset(20)
204+
```
205+
206+
> <img src="./assets/images/numbers.png" width="428" height="152">
207+
147208
#### 🔗 Unencode HTML
148209

149210
Input may contain HTML entities such as `&lt;` which will not be parsed by LaTeX as anything meaningful. In this case, you may use the `unencoded` modifier.
@@ -152,25 +213,16 @@ Input may contain HTML entities such as `&lt;` which will not be parsed by LaTeX
152213
LaTeX("$x^2&lt;1$")
153214
.errorMode(.error)
154215

155-
// Replace "lt;" with "<"
216+
// Replace "&lt;" with "<"
156217
LaTeX("$x^2&lt;1$")
157218
.unencoded()
158219
```
159220

160221
> <img src="./assets/images/unencoded.png" width="72.5" height="34">
161222
162-
#### ♾️ TeX Options
163-
164-
For more control over the MathJax rendering, you can pass a `TeXInputProcessorOptions` object to the view.
165-
166-
```swift
167-
LaTeX("Hello, $\\LaTeX$!")
168-
.texOptions(TeXInputProcessorOptions(loadPackages: [TeXInputProcessorOptions.Packages.base]))
169-
```
170-
171223
### 🗄️ Caching
172224

173-
`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 `cache` property.
225+
`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.
174226

175227
The caches are managed automatically, but if, for example, you wanted to clear the cache manually you may do so.
176228

@@ -188,10 +240,17 @@ LaTeX.imageCache.removeAll()
188240

189241
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.
190242

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+
191245
```swift
192246
VStack {
193247
ForEach(expressions, id: \.self) { expression in
194248
LaTeX(expression)
249+
.font(.caption2)
250+
.foregroundColor(.green)
251+
.unencoded()
252+
.errorMode(.error)
253+
.processEscapes()
195254
.preload()
196255
}
197256
}

Sources/LaTeXSwiftUI/Extensions/EnvironmentValues+Extensions.swift

Lines changed: 36 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,20 @@ private struct BlockModeKey: EnvironmentKey {
4646
static let defaultValue: LaTeX.BlockMode = .blockViews
4747
}
4848

49-
private struct TeXInputProcessorOptionsKey: EnvironmentKey {
50-
static let defaultValue: TeXInputProcessorOptions = TeXInputProcessorOptions(loadPackages: TeXInputProcessorOptions.Packages.all)
49+
private struct ProcessEscapesKey: EnvironmentKey {
50+
static let defaultValue: Bool = false
51+
}
52+
53+
private struct EquationNumberModeKey: EnvironmentKey {
54+
static let defaultValue: LaTeX.EquationNumberMode = .none
55+
}
56+
57+
private struct EquationNumberStartKey: EnvironmentKey {
58+
static let defaultValue: Int = 1
59+
}
60+
61+
private struct EquationNumberOffsetKey: EnvironmentKey {
62+
static let defaultValue: CGFloat = 0.0
5163
}
5264

5365
extension EnvironmentValues {
@@ -82,10 +94,28 @@ extension EnvironmentValues {
8294
set { self[BlockModeKey.self] = newValue }
8395
}
8496

85-
/// The TeX options of this environment.
86-
var texOptions: TeXInputProcessorOptions {
87-
get { self[TeXInputProcessorOptionsKey.self] }
88-
set { self[TeXInputProcessorOptionsKey.self] = newValue }
97+
/// The processEscapes value of this environment.
98+
var processEscapes: Bool {
99+
get { self[ProcessEscapesKey.self] }
100+
set { self[ProcessEscapesKey.self] = newValue }
101+
}
102+
103+
/// The equation number mode of this environment.
104+
var equationNumberMode: LaTeX.EquationNumberMode {
105+
get { self[EquationNumberModeKey.self] }
106+
set { self[EquationNumberModeKey.self] = newValue }
107+
}
108+
109+
/// The equation starting number of this environment.
110+
var equationNumberStart: Int {
111+
get { self[EquationNumberStartKey.self] }
112+
set { self[EquationNumberStartKey.self] = newValue }
113+
}
114+
115+
/// The equation number offset of this environment.
116+
var equationNumberOffset: CGFloat {
117+
get { self[EquationNumberOffsetKey.self] }
118+
set { self[EquationNumberOffsetKey.self] = newValue }
89119
}
90120

91121
}

Sources/LaTeXSwiftUI/Extensions/View+Extensions.swift

Lines changed: 69 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,31 @@ import SwiftUI
2828

2929
public extension View {
3030

31+
/// Preloads a `LaTeX` view's SVG and image data.
32+
///
33+
/// This method should be called last in the view's modifier chain (if at
34+
/// all).
35+
///
36+
/// - Example:
37+
///
38+
/// ```
39+
/// LaTeX("Hello, $\\LaTeX$!")
40+
/// .font(.title)
41+
/// .processEscapes()
42+
/// .preload()
43+
/// ```
44+
///
45+
/// - Note: If the receiver isn't a `LaTeX` view, then this method does
46+
/// nothing.
47+
///
48+
/// - Returns: A preloaded view.
49+
@MainActor func preload() -> some View {
50+
if let latex = self as? LaTeX {
51+
latex.preload()
52+
}
53+
return self
54+
}
55+
3156
/// Sets the image rendering mode for images rendered by MathJax.
3257
///
3358
/// - Parameter mode: The template rendering mode.
@@ -47,9 +72,10 @@ public extension View {
4772

4873
/// Unencodes HTML input text.
4974
///
75+
/// - Parameter unencode: Whether the variable should be set to true or false.
5076
/// - Returns: A view that displays unencoded text.
51-
func unencoded() -> some View {
52-
environment(\.unencodeHTML, true)
77+
func unencoded(_ unencode: Bool = true) -> some View {
78+
environment(\.unencodeHTML, unencode)
5379
}
5480

5581
/// Sets the parsing mode to use when parsing LaTeX input.
@@ -68,14 +94,47 @@ public extension View {
6894
environment(\.blockMode, mode)
6995
}
7096

71-
/// Sets the TeX options for any images rendered with MathJax in this
72-
/// environment.
73-
///
74-
/// - Parameter options: The TeX input processor options.
75-
/// - Returns: A view that uses the given TeX input processor options to
76-
/// render images in its view.
77-
func texOptions(_ options: TeXInputProcessorOptions) -> some View {
78-
environment(\.texOptions, options)
97+
/// When set to `true`, you may use `\$` to represent a literal dollar sign,
98+
/// rather than using it as a math delimiter, and `\\` to represent a literal
99+
/// backslash (so that you can use `\\\$` to get a literal `\$` or `\\$...$`
100+
/// to get a backslash just before in-line math).
101+
///
102+
/// When `false`, `\$` will not be altered, and its dollar sign may be
103+
/// considered part of a math delimiter. Typically this is set to `true` if
104+
/// you enable the `$ ... $` in-line delimiters, so you can type `\$` and
105+
/// MathJax will convert it to a regular dollar sign in the rendered document.
106+
///
107+
/// - Reference: [Option Descriptions](https://docs.mathjax.org/en/latest/options/input/tex.html#option-descriptions)
108+
///
109+
/// - Parameter process: Whether escapes should be processed.
110+
/// - Returns: A view that processes escapes in its text input.
111+
func processEscapes(_ process: Bool = true) -> some View {
112+
environment(\.processEscapes, process)
113+
}
114+
115+
/// Sets whether block view equation numbers should be hidden, displayed on
116+
/// the left side of an equation, or displayed on the right side.
117+
///
118+
/// - Parameter mode: The equation number mode.
119+
/// - Returns: A view that numbers its equations.
120+
func equationNumberMode(_ mode: LaTeX.EquationNumberMode) -> some View {
121+
environment(\.equationNumberMode, mode)
122+
}
123+
124+
/// Sets the starting value for equation numbers in this view.
125+
///
126+
/// - Parameter value: The starting value.
127+
/// - Returns: A view that numbers its equations.
128+
func equationNumberStart(_ value: Int) -> some View {
129+
environment(\.equationNumberStart, value)
130+
}
131+
132+
/// Sets the number's left or right offset.
133+
///
134+
/// - Parameter offset: The offset to set.
135+
/// - Returns: A view that numbers its equations.
136+
func equationNumberOffset(_ offset: CGFloat) -> some View {
137+
environment(\.equationNumberOffset, offset)
79138
}
80139

81140
}

0 commit comments

Comments
 (0)