Skip to content

Commit e60270c

Browse files
authored
Merge pull request #55 from colinc86/develop
Bug fixes and enhancements
2 parents b5f9018 + 069496c commit e60270c

26 files changed

+999
-605
lines changed

Package.resolved

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

Package.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ import PackageDescription
66
let package = Package(
77
name: "LaTeXSwiftUI",
88
platforms: [
9-
.iOS(.v16),
10-
.macOS(.v13)
9+
.iOS(.v15),
10+
.macOS(.v12)
1111
],
1212
products: [
1313
.library(
@@ -16,15 +16,15 @@ let package = Package(
1616
],
1717
dependencies: [
1818
.package(url: "https://github.com/colinc86/MathJaxSwift", from: "3.4.0"),
19-
.package(url: "https://github.com/exyte/SVGView", from: "1.0.4"),
19+
.package(url: "https://github.com/colinc86/SwiftDraw", branch: "latexswiftui"),
2020
.package(url: "https://github.com/Kitura/swift-html-entities", from: "4.0.1")
2121
],
2222
targets: [
2323
.target(
2424
name: "LaTeXSwiftUI",
2525
dependencies: [
2626
"MathJaxSwift",
27-
"SVGView",
27+
"SwiftDraw",
2828
.product(name: "HTMLEntities", package: "swift-html-entities")
2929
]),
3030
.testTarget(

README.md

Lines changed: 63 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -8,27 +8,28 @@ A SwiftUI view that renders LaTeX equations.
88

99
## 📖 Contents
1010

11-
- [About](#ℹ️-about)
12-
- [Installation](#📦-installation)
13-
- [Usage](#⌨️-usage)
14-
- [Modifiers](#⚙️-modifiers)
15-
- [Parsing Mode](#🔤-parsing-mode)
16-
- [Image Rendering Mode](#🌄-image-rendering-mode)
17-
- [Error Mode](#🚨-error-mode)
18-
- [Block Rendering Mode](#🧱-block-rendering-mode)
19-
- [Numbered Block Equations](#🔢-numbered-block-equations)
11+
- [ℹ️ About](#about)
12+
- [📦 Installation](#installation)
13+
- [⌨️ Usage](#usage)
14+
- [⚙️ Modifiers](#modifiers)
15+
- [🔤 Parsing Mode](#parsing-mode)
16+
- [🌄 Image Rendering Mode](#image-rendering-mode)
17+
- [🚨 Error Mode](#error-mode)
18+
- [🧱Block Rendering Mode](#block-rendering-mode)
19+
- [🔢 Numbered Block Equations](#numbered-block-equations)
2020
- [Equation Number Mode](#equation-number-mode)
2121
- [Equation Number Start](#equation-number-start)
2222
- [Equation Number Offset](#equation-number-offset)
2323
- [Format Equation Number](#format-equation-number)
24-
- [Unencode HTML](#🔗-unencode-html)
25-
- [Rendering Style](#🕶️-rendering-style)
26-
- [Rendering Animation](#🪩-animated)
27-
- [Styles](#🪮-styles)
28-
- [Caching](#🗄️-caching)
29-
- [Preloading](#🏃‍♀️-preloading)
24+
- [🔗 Unencode HTML](#unencode-html)
25+
- [📄 Ignore String Formatting](#ignore-string-formatting)
26+
- [🕶️ Rendering Style](#rendering-style)
27+
- [🪩 Rendering Animation](#rendering-animation)
28+
- [🪮 Styles](#styles)
29+
- [🗄️ Caching](#caching)
30+
- [🏃‍♀️ Preloading](#preloading)
3031

31-
## ℹ️ About
32+
## About
3233

3334
`LaTexSwiftUI` is a package that exposes a view named `LaTeX` that can parse and render TeX and LaTeX equations which contain math-mode macros.
3435

@@ -43,15 +44,15 @@ It will
4344
It won't
4445
- render TeX and LaTeX documents (text-mode macros, with the exception of the rule above).
4546

46-
## 📦 Installation
47+
## Installation
4748

4849
Add the dependency to your package manifest file.
4950

5051
```swift
5152
.package(url: "https://github.com/colinc86/LaTeXSwiftUI", from: "1.3.2")
5253
```
5354

54-
## ⌨️ Usage
55+
## Usage
5556

5657
Import the package and use the view.
5758

@@ -69,7 +70,7 @@ struct MyView: View {
6970

7071
> <img src="./assets/images/hello.png" width="85" height="21.5">
7172
72-
### ⚙️ Modifiers
73+
### Modifiers
7374

7475
The `LaTeX` view's body is built up of `Text` views so feel free to use any of the supported modifiers.
7576

@@ -83,14 +84,15 @@ LaTeX("Hello, $\\LaTeX$!")
8384
8485
Along with supporting the built-in SwiftUI modifies, `LaTeXSwiftUI` defines more to let you configure the view.
8586

86-
#### 🔤 Parsing Mode
87+
#### Parsing Mode
8788

8889
Text input can either be completely rendered, or the view can search for top-level equations delimited by the following terminators.
8990

9091
| Terminators |
9192
|-------------|
9293
| `$...$` |
9394
| `$$...$$` |
95+
| `\(...\)` |
9496
| `\[...\]` |
9597
| `\begin{equation}...\end{equation}` |
9698
| `\begin{equation*}...\end{equation*}` |
@@ -110,7 +112,7 @@ LaTeX("\\text{Euler's identity is } e^{i\\pi}+1=0\\text{.}")
110112

111113
> <img src="./assets/images/euler.png" width="293" height="80">
112114
113-
#### 🌄 Image Rendering Mode
115+
#### Image Rendering Mode
114116

115117
You can specify the rendering mode of the rendered equations so that they either take on the style of the surrounding text or display the style rendered by MathJax. The default behavior is to use the `template` rendering mode so that images match surrounding text.
116118

@@ -126,7 +128,7 @@ LaTeX("Hello, ${\\color{red} \\LaTeX}$!")
126128

127129
> <img src="./assets/images/rendering_mode.png" width="84.5" height="43">
128130
129-
#### 🚨 Error Mode
131+
#### Error Mode
130132

131133
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`.
132134

@@ -148,7 +150,7 @@ LaTeX("$\\asdf$")
148150

149151
> <img src="./assets/images/errors.png" width="199.5" height="55">
150152
151-
#### 🧱 Block Rendering Mode
153+
#### Block Rendering Mode
152154

153155
The typical "LaTeX-ish" way to render the input is with `blockViews`. This mode renders text as usual, and block equations as... blocks; on their own line and centered. MathJax 3 does not support line breaking, so the view places block equations in horizontal scroll views in case the width of the equation is more than the width of the view.
154156

@@ -174,7 +176,7 @@ LaTeX("The quadratic formula is $$x=\\frac{-b\\pm\\sqrt{b^2-4ac}}{2a}$$ and it h
174176

175177
> <img src="./assets/images/blocks.png" width="430" height="350">
176178
177-
#### 🔢 Numbered Block Equations
179+
#### Numbered Block Equations
178180

179181
The `LaTeX` view can do simple numbering of block equations with the `blockViews` block mode.
180182

@@ -211,7 +213,7 @@ LaTeX("$$E = mc^2$$ $$E = mc^2$$")
211213

212214
> <img src="./assets/images/numbers.png" width="433" height="153">
213215
214-
#### 🔗 Unencode HTML
216+
#### Unencode HTML
215217

216218
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.
217219

@@ -226,19 +228,46 @@ LaTeX("$x^2&lt;1$")
226228

227229
> <img src="./assets/images/unencoded.png" width="72.5" height="34">
228230
229-
#### 🕶️ Rendering Style
231+
#### Ignore String Formatting
232+
233+
The `LaTeX` view will render the following markdown synatax.
234+
235+
| Syntax | Description |
236+
|-------------|-------------|
237+
| `*...*` | Italic |
238+
| `**...**` | Bold |
239+
| `***...***` | Bold & Italic |
240+
| `~~...~~` | Strikethrough |
241+
| `` `...` `` | Monospaced |
242+
| `[...](...)` | Links |
243+
244+
If you don't want markdown rendered, then you may use the `ignoreStringFormatting` modifier.
245+
246+
```swift
247+
LaTeX(input)
248+
.ignoreStringFormatting()
249+
```
250+
251+
##### Escaped Characters
252+
253+
The characeters `&`, `%`, `$`, `#`, `_`, `{`, `}`, `~`, `^`, and `\` are reserved characters in LaTeX and may appear in a document with an escape characeter preceeding them.
254+
255+
The view will look for these characters preceeded by an escape, and replace them with the non-escaped version. If you would like to prevent this replacement, then you may use the `ignoreStringFormatting` modifier.
256+
257+
#### Rendering Style
230258

231259
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.
232260

233261
| Style | Asynchronous | Description |
234262
|:-----------|:-------------|:-------------------------------------------------------------------------|
235-
| `empty` | Yes | The view remains empty until its finished rendering. |
236-
| `original` | Yes | The view displays the input text until its finished rendering. |
237-
| `progress` | Yes | The view displays a progress view until its finished rendering. |
238-
| `wait` | No | *(default)* The view blocks the main queue until its finished rendering. |
263+
| `empty` | Yes | The view remains empty until it's finished rendering. |
264+
| `original` | Yes | The view displays the input text until it's finished rendering. |
265+
| `redactedOriginal` | Yes | The view displays a redacted version of the view until it's finished rendering |
266+
| `progress` | Yes | The view displays a progress view until it's finished rendering. |
267+
| `wait` | No | *(default)* The view blocks the main queue until it's finished rendering. |
239268

240269

241-
#### 🪩 Rendering Animation
270+
#### Rendering Animation
242271

243272
When using the asynchronous rendering styles `empty`, `original`, or `progress`, use this modifier to determine the animation applied to the transition between views. The default value is `none`.
244273

@@ -250,7 +279,7 @@ LaTeX(input)
250279

251280
> 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.
252281
253-
### 🪮 Styles
282+
### Styles
254283

255284
You can use the provided view styles or create your own.
256285

@@ -288,7 +317,7 @@ public struct TitleLaTeXStyle: LaTeXStyle {
288317
}
289318
```
290319

291-
### 🗄️ Caching
320+
### Caching
292321

293322
`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.
294323

@@ -300,7 +329,7 @@ LaTeX.dataCache.removeAllObjects()
300329
LaTeX.imageCache.removeAllObjects()
301330
```
302331

303-
### 🏃‍♀️ Preloading
332+
### Preloading
304333

305334
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.
306335

Sources/LaTeXSwiftUI/Extensions/EnvironmentValues+Extensions.swift

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,10 @@ private struct RenderingAnimationKey: EnvironmentKey {
7474
static let defaultValue: Animation? = .none
7575
}
7676

77+
private struct IgnoreSringFormatting: EnvironmentKey {
78+
static let defaultValue: Bool = false
79+
}
80+
7781
extension EnvironmentValues {
7882

7983
/// The image rendering mode of this environment.
@@ -148,4 +152,10 @@ extension EnvironmentValues {
148152
set { self[RenderingAnimationKey.self] = newValue }
149153
}
150154

155+
/// Whether string formatting such as markdown should be ignored or rendered.
156+
var ignoreStringFormatting: Bool {
157+
get { self[IgnoreSringFormatting.self] }
158+
set { self[IgnoreSringFormatting.self] = newValue }
159+
}
160+
151161
}

Sources/LaTeXSwiftUI/Extensions/Image+Extensions.swift

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -27,24 +27,27 @@ import SwiftUI
2727

2828
internal extension Image {
2929

30-
init(image: _Image) {
30+
init(image: _Image, scale: CGFloat = 1.0) {
3131
#if os(iOS)
3232
self.init(uiImage: image)
3333
#else
34+
if scale > 1.0 {
35+
let scaledSize = NSSize(
36+
width: image.size.width / scale,
37+
height: image.size.height / scale
38+
)
39+
40+
let scaledImage = image.resized(to: scaledSize)
41+
if let representation = image.representations.first {
42+
scaledImage.addRepresentation(representation)
43+
}
44+
45+
self.init(nsImage: scaledImage)
46+
return
47+
}
48+
3449
self.init(nsImage: image)
3550
#endif
3651
}
3752

3853
}
39-
40-
internal extension _Image {
41-
42-
convenience init?(imageData: Data, scale: CGFloat? = nil) {
43-
#if os(iOS)
44-
self.init(data: imageData, scale: scale ?? 1)
45-
#else
46-
self.init(data: imageData)
47-
#endif
48-
}
49-
50-
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
//
2+
// NSImage+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+
#if os(macOS)
27+
import Cocoa
28+
29+
internal extension NSImage {
30+
31+
/// Resizes the image.
32+
/// - Parameter newSize: The image's new size.
33+
/// - Returns: A resized image.
34+
func resized(to newSize: CGSize) -> NSImage {
35+
let newImage = NSImage(size: newSize)
36+
newImage.lockFocus()
37+
defer { newImage.unlockFocus() }
38+
self.draw(
39+
in: CGRect(origin: .zero, size: newSize),
40+
from: CGRect(origin: .zero, size: self.size),
41+
operation: .copy,
42+
fraction: 1.0)
43+
return newImage
44+
}
45+
46+
}
47+
#endif

Sources/LaTeXSwiftUI/Extensions/TeXInputProcessorOptions+Extensions.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,11 @@ extension TeXInputProcessorOptions {
4848
}
4949
}
5050
loadPackages = packages
51+
52+
// The default inlineMath for MathJax is set to [["\\(", "\\)"]] which isn't
53+
// useful for this package since we'd rather use dollar signs and reserve
54+
// parentheses for grouping symbols.
55+
inlineMath = [["$", "$"]]
5156
}
5257

5358
}

0 commit comments

Comments
 (0)