Skip to content

Commit

Permalink
refactor: Move Live Preview & Syntax Check to Rust-Swift Bridge
Browse files Browse the repository at this point in the history
This would hopefully improve the performance of the app.

Signed-off-by: Qian Qian "Cubik"‎ <[email protected]>
  • Loading branch information
Cubik65536 committed Aug 14, 2024
1 parent 6ca6ab2 commit c2d61f9
Show file tree
Hide file tree
Showing 21 changed files with 3,060 additions and 149 deletions.
2,540 changes: 2,457 additions & 83 deletions Cargo.lock

Large diffs are not rendered by default.

22 changes: 22 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,25 @@ crate-type = ["staticlib"]

[dependencies]
swift-bridge = "0.1"

# typst essentials
typst = "0.11.0"
comemo = "0.4"

# typst rendering
typst-pdf = "0.11.0"
typst-svg = "0.11.0"

# Fetching and unzipping packages
zune-inflate = { version = "0.2", default_features = false, features = [
"gzip",
"std",
] }
tar = "0.4"
ureq = "2.9"

# utils
time = "0.3"
ttf-parser = "0.24.0"
thiserror = "1.0.63"
urlencoding = "2.1.3"
9 changes: 4 additions & 5 deletions Typstify/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ Typst, designed as an alternative for LaTeX, can be very useful for students for
- [x] Real-Time PDF Preview
- [x] Real-Time Syntax Error Check
- [x] Access to Online Packages
- [x] Image Insertion
- [ ] Image Insertion
- [ ] Syntax Highlighting
- [ ] Sketching
- [ ] Drag-and-Drop Support
Expand Down Expand Up @@ -69,10 +69,9 @@ If you're interested, please consider sponsoring the project via [GitHub Sponsor

This project relies on these open source projects:

- [typst-library-swift](https://github.com/iXORTech/typst-library-swift): A bridge that allows Swift apps to communicate with the Typst library, written in Rust. Which relies on:
- [Typst Libraries](https://crates.io/crates/typst) for [Typst](https://typst.app) related functionality such as Typst document rendering and syntax check.
- [cargo-swift](https://github.com/antoniusnaumann/cargo-swift) for building Swift packages from Rust code.
- [tfachmann/typst-as-library](https://github.com/tfachmann/typst-as-library) for providing a wrapper around the Typst Library.
- [Typst Libraries](https://crates.io/crates/typst) for [Typst](https://typst.app) related functionality such as Typst document rendering and syntax check.
- [tfachmann/typst-as-library](https://github.com/tfachmann/typst-as-library) for providing a wrapper around the Typst Library.
- [chinedufn/swift-bridge](https://github.com/chinedufn/swift-bridge) for enabling Swift-Rust interoperability.
- [mchakravarty/CodeEditorView](https://github.com/mchakravarty/CodeEditorView): A SwiftUI code editor view for iOS, visionOS, and macOS
- [mchakravarty/ProjectNavigator](https://github.com/mchakravarty/ProjectNavigator): A SwiftUI project navigation view for macOS and iOS

Expand Down
11 changes: 1 addition & 10 deletions Typstify/Typstify-Bridging-Header.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,12 @@
// Created by Cubik65536 on 2024-08-04.
//

// This is to prevent PDFView from stealing first responder when setting document.
// https://gist.github.com/chbeer/5a4506d6e657c3b3ea3fdfd0391c9028

// I just migrated part of https://github.com/defagos/CoconutKit (the parts needed, HLSRuntime and HLSWeakObjectWrapper)
// to make this work. CoconutKit is distributed under MIT license.

// I know this is a very hacky workaround, but I don't have a better solution for now.
// If you do have a better solution, please do help me.

#import "SwizzleHelper.h"

#ifndef BridgingHeader_h
#define BridgingHeader_h

#include "Generated/SwiftBridgeCore.h"
#include "Generated/typstify/typstify-rust-library.h"
#include "Generated/typstify-rust-library/typstify-rust-library.h"

#endif
54 changes: 36 additions & 18 deletions Typstify/Typstify.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@
objects = {

/* Begin PBXBuildFile section */
3E0295B02C6C48CB00A4F20C /* .gitignore in Resources */ = {isa = PBXBuildFile; fileRef = 3E0295AC2C6C48CB00A4F20C /* .gitignore */; };
3E0295B12C6C48CB00A4F20C /* typstify-rust-library.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3E0295AA2C6C48CB00A4F20C /* typstify-rust-library.swift */; };
3E0295B22C6C48CB00A4F20C /* SwiftBridgeCore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3E0295AE2C6C48CB00A4F20C /* SwiftBridgeCore.swift */; };
3E1002632C5C222400A9E0C7 /* PhotosPickerItemExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3E1002622C5C221D00A9E0C7 /* PhotosPickerItemExtension.swift */; };
3E2AD0C42C57372F005A85AB /* CodeEditorView in Frameworks */ = {isa = PBXBuildFile; productRef = 3E2AD0C32C57372F005A85AB /* CodeEditorView */; };
3E2AD0C62C57372F005A85AB /* LanguageSupport in Frameworks */ = {isa = PBXBuildFile; productRef = 3E2AD0C52C57372F005A85AB /* LanguageSupport */; };
Expand All @@ -28,6 +31,11 @@
/* End PBXBuildFile section */

/* Begin PBXFileReference section */
3E0295A92C6C48CB00A4F20C /* typstify-rust-library.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "typstify-rust-library.h"; sourceTree = "<group>"; };
3E0295AA2C6C48CB00A4F20C /* typstify-rust-library.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "typstify-rust-library.swift"; sourceTree = "<group>"; };
3E0295AC2C6C48CB00A4F20C /* .gitignore */ = {isa = PBXFileReference; lastKnownFileType = text; path = .gitignore; sourceTree = "<group>"; };
3E0295AD2C6C48CB00A4F20C /* SwiftBridgeCore.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SwiftBridgeCore.h; sourceTree = "<group>"; };
3E0295AE2C6C48CB00A4F20C /* SwiftBridgeCore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftBridgeCore.swift; sourceTree = "<group>"; };
3E0304FA2C6AE9E500EF4D87 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = "<group>"; };
3E1002622C5C221D00A9E0C7 /* PhotosPickerItemExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhotosPickerItemExtension.swift; sourceTree = "<group>"; };
3E2AD0CB2C574B1A005A85AB /* TypstifyDocumentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TypstifyDocumentView.swift; sourceTree = "<group>"; };
Expand All @@ -43,10 +51,6 @@
3EBA29B42C55D7D000ACBAD3 /* LICENSE */ = {isa = PBXFileReference; lastKnownFileType = text; path = LICENSE; sourceTree = "<group>"; };
3ED48E152C6C345000396903 /* Typstify-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Typstify-Bridging-Header.h"; sourceTree = "<group>"; };
3ED48E172C6C360B00396903 /* libtypstify_rust_library.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libtypstify_rust_library.a; path = ../target/universal/debug/libtypstify_rust_library.a; sourceTree = "<group>"; };
3ED48E192C6C36B900396903 /* SwiftBridgeCore.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SwiftBridgeCore.h; path = Generated/SwiftBridgeCore.h; sourceTree = "<group>"; };
3ED48E1A2C6C36B900396903 /* SwiftBridgeCore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = SwiftBridgeCore.swift; path = Generated/SwiftBridgeCore.swift; sourceTree = "<group>"; };
3ED48E1B2C6C36B900396903 /* typstify-rust-library.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "typstify-rust-library.h"; sourceTree = "<group>"; };
3ED48E1C2C6C36B900396903 /* typstify-rust-library.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "typstify-rust-library.swift"; sourceTree = "<group>"; };
3EE1AA682C60698D003C913A /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
3EE1AA802C606CF6003C913A /* HLSRuntime.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = HLSRuntime.h; sourceTree = "<group>"; };
3EE1AA812C606CF6003C913A /* HLSRuntime.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = HLSRuntime.m; sourceTree = "<group>"; };
Expand All @@ -73,12 +77,30 @@
/* End PBXFrameworksBuildPhase section */

/* Begin PBXGroup section */
3E0295AB2C6C48CB00A4F20C /* typstify-rust-library */ = {
isa = PBXGroup;
children = (
3E0295A92C6C48CB00A4F20C /* typstify-rust-library.h */,
3E0295AA2C6C48CB00A4F20C /* typstify-rust-library.swift */,
);
path = "typstify-rust-library";
sourceTree = "<group>";
};
3E0295AF2C6C48CB00A4F20C /* Generated */ = {
isa = PBXGroup;
children = (
3E0295AB2C6C48CB00A4F20C /* typstify-rust-library */,
3E0295AC2C6C48CB00A4F20C /* .gitignore */,
3E0295AD2C6C48CB00A4F20C /* SwiftBridgeCore.h */,
3E0295AE2C6C48CB00A4F20C /* SwiftBridgeCore.swift */,
);
path = Generated;
sourceTree = "<group>";
};
3E57044E2C555BB9003233AA = {
isa = PBXGroup;
children = (
3ED48E1D2C6C36B900396903 /* typstify-rust-library */,
3ED48E192C6C36B900396903 /* SwiftBridgeCore.h */,
3ED48E1A2C6C36B900396903 /* SwiftBridgeCore.swift */,
3E0295AF2C6C48CB00A4F20C /* Generated */,
3ED48E152C6C345000396903 /* Typstify-Bridging-Header.h */,
3E5704592C555BB9003233AA /* Typstify */,
3EBA29B42C55D7D000ACBAD3 /* LICENSE */,
Expand Down Expand Up @@ -137,23 +159,14 @@
name = Frameworks;
sourceTree = "<group>";
};
3ED48E1D2C6C36B900396903 /* typstify-rust-library */ = {
isa = PBXGroup;
children = (
3ED48E1B2C6C36B900396903 /* typstify-rust-library.h */,
3ED48E1C2C6C36B900396903 /* typstify-rust-library.swift */,
);
path = "typstify-rust-library";
sourceTree = "<group>";
};
/* End PBXGroup section */

/* Begin PBXNativeTarget section */
3E5704562C555BB9003233AA /* Typstify */ = {
isa = PBXNativeTarget;
buildConfigurationList = 3E5704652C555BBA003233AA /* Build configuration list for PBXNativeTarget "Typstify" */;
buildPhases = (
3ED48E142C6C33BB00396903 /* ShellScript */,
3E0295B32C6C538500A4F20C /* ShellScript */,
3E5704532C555BB9003233AA /* Sources */,
3E5704542C555BB9003233AA /* Frameworks */,
3E5704552C555BB9003233AA /* Resources */,
Expand Down Expand Up @@ -216,14 +229,15 @@
buildActionMask = 2147483647;
files = (
3E5704622C555BBA003233AA /* Preview Assets.xcassets in Resources */,
3E0295B02C6C48CB00A4F20C /* .gitignore in Resources */,
3E57045F2C555BBA003233AA /* Assets.xcassets in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */

/* Begin PBXShellScriptBuildPhase section */
3ED48E142C6C33BB00396903 /* ShellScript */ = {
3E0295B32C6C538500A4F20C /* ShellScript */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
Expand All @@ -249,6 +263,8 @@
files = (
3EE1AA692C606990003C913A /* AppDelegate.swift in Sources */,
3EE1AA862C606CF6003C913A /* HLSRuntime.m in Sources */,
3E0295B12C6C48CB00A4F20C /* typstify-rust-library.swift in Sources */,
3E0295B22C6C48CB00A4F20C /* SwiftBridgeCore.swift in Sources */,
3E2D55BD2C61A17A00F24C26 /* Hashing.swift in Sources */,
3EE1AA872C606CF6003C913A /* SwizzleHelper.m in Sources */,
3E2D55C62C61B60A00F24C26 /* ViewContext.swift in Sources */,
Expand Down Expand Up @@ -393,6 +409,7 @@
DEVELOPMENT_ASSET_PATHS = "\"Typstify/Preview Content\"";
DEVELOPMENT_TEAM = QT93JJ48BC;
ENABLE_PREVIEWS = YES;
ENABLE_USER_SCRIPT_SANDBOXING = NO;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = Typstify/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = Typstify;
Expand Down Expand Up @@ -435,6 +452,7 @@
DEVELOPMENT_ASSET_PATHS = "\"Typstify/Preview Content\"";
DEVELOPMENT_TEAM = QT93JJ48BC;
ENABLE_PREVIEWS = YES;
ENABLE_USER_SCRIPT_SANDBOXING = NO;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = Typstify/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = Typstify;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Bucket
uuid = "B91EF004-370E-42B8-9F0F-D73288AA3DBD"
type = "1"
version = "2.0">
</Bucket>
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,36 @@
<key>isShown</key>
<false/>
<key>orderHint</key>
<integer>3</integer>
<integer>2</integer>
</dict>
<key>CodeEditor (Playground) 2.xcscheme</key>
<dict>
<key>isShown</key>
<false/>
<key>orderHint</key>
<integer>3</integer>
</dict>
<key>CodeEditor (Playground) 3.xcscheme</key>
<dict>
<key>isShown</key>
<false/>
<key>orderHint</key>
<integer>4</integer>
</dict>
<key>CodeEditor (Playground) 4.xcscheme</key>
<dict>
<key>isShown</key>
<false/>
<key>orderHint</key>
<integer>5</integer>
</dict>
<key>CodeEditor (Playground) 5.xcscheme</key>
<dict>
<key>isShown</key>
<false/>
<key>orderHint</key>
<integer>6</integer>
</dict>
<key>CodeEditor (Playground).xcscheme</key>
<dict>
<key>isShown</key>
Expand All @@ -28,7 +49,7 @@
<key>Typstify.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>0</integer>
<integer>1</integer>
</dict>
</dict>
</dict>
Expand Down
35 changes: 16 additions & 19 deletions Typstify/Typstify/ContentView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import SwiftUI
import CodeEditorView
import LanguageSupport
import ProjectNavigator
import TypstLibrarySwift

// MARK: -
// MARK: UUID serialisation
Expand Down Expand Up @@ -54,18 +53,16 @@ struct DocumentView: View {
} catch let error as TypstCompilationError {
let diagnostics = error.diagnostics()
diagnostics.forEach { diagnostic in
let line = diagnostic.lineStart
let column = diagnostic.columnStart
let line = diagnostic.line_start()
let column = diagnostic.column_start()

let category = switch diagnostic.severity {
case SourceDiagnosticResultSeverity.error:
Message.Category.error
case SourceDiagnosticResultSeverity.warning:
Message.Category.warning
let category = switch diagnostic.severity() {
case .Error: Message.Category.error
case .Warning: Message.Category.warning
}

let length = diagnostic.columnEnd - diagnostic.columnStart
let summary = diagnostic.message
let length = diagnostic.column_end() - diagnostic.column_start()
let summary = diagnostic.message().toString()

messages.insert(
TextLocated(
Expand Down Expand Up @@ -436,15 +433,15 @@ struct ContentView: View {
print("documents directory: \(URL.documentsDirectory)")
print("file url: \(String(describing: projectURL?.path()))")

if projectURL != nil {
do {
try TypstLibrarySwift.setWorkingDirectory(path: (
projectURL?.path()
)!)
} catch {
print("Failed to set working directory. Error: \(error)")
}
}
// if projectURL != nil {
// do {
// try TypstLibrarySwift.setWorkingDirectory(path: (
// projectURL?.path()
// )!)
// } catch {
// print("Failed to set working directory. Error: \(error)")
// }
// }

if let savedSelection = selection {
fileNavigationViewState.selection = savedSelection
Expand Down
9 changes: 6 additions & 3 deletions Typstify/Typstify/TypstifyDocument.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import UniformTypeIdentifiers
import Observation
import os

import TypstLibrarySwift

private let logger = Logger(subsystem: "dev.ixor.Typstify", category: "Typstify")

Expand All @@ -23,8 +22,12 @@ extension UTType {
}

func renderTypstDocument(from source: String) throws -> PDFDocument? {
let document = try TypstLibrarySwift.getRenderedDocumentPdf(source: source)
return PDFDocument(data: document)
let document = try get_rendered_document_pdf(source)
var elements: Array<UInt8> = Array()
for value in document {
elements.append(value)
}
return PDFDocument(data: Data(elements))
}

// MARK: -
Expand Down
15 changes: 15 additions & 0 deletions Typstify/build-rust.sh
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,18 @@ fi
# echo "Skipping the script because of preview mode"
# fi

# Added for now to make `throw TypstCompilationError` work
# Related issue:
# - https://github.com/chinedufn/swift-bridge/issues/260
# - https://github.com/chinedufn/swift-bridge/issues/150
fileContent=$(<Generated/typstify-rust-library/typstify-rust-library.swift)
if [[ $fileContent == *"extension TypstCompilationError: @unchecked Sendable {}"* ]]; then
echo "Skipping adding extension TypstCompilationError: @unchecked Sendable {}"
else
echo "extension TypstCompilationError: @unchecked Sendable {}" >> Generated/typstify-rust-library/typstify-rust-library.swift
fi
if [[ $fileContent == *"extension TypstCompilationError: Error {}"* ]]; then
echo "Skipping adding extension TypstCompilationError: Error {}"
else
echo "extension TypstCompilationError: Error {}" >> Generated/typstify-rust-library/typstify-rust-library.swift
fi
Binary file added embedded-fonts/CMUConcrete.ttf
Binary file not shown.
Binary file added embedded-fonts/CMUSansSerif.ttf
Binary file not shown.
Binary file added embedded-fonts/CMUSerif.ttf
Binary file not shown.
Binary file added embedded-fonts/CMUTypewriter.ttf
Binary file not shown.
Binary file added embedded-fonts/IBMPlexMono.ttf
Binary file not shown.
Binary file added embedded-fonts/IBMPlexSans.ttf
Binary file not shown.
Binary file added embedded-fonts/IBMPlexSerif.ttf
Binary file not shown.
Binary file added embedded-fonts/LXGWWenKaiMonoLite.ttf
Binary file not shown.
Binary file added embedded-fonts/STIXTwoMath-Regular.ttf
Binary file not shown.
Loading

0 comments on commit c2d61f9

Please sign in to comment.