Commit dece66c32a

dece66c32a50c8dc3f1134f9d32696f5c45192c7

parent: f9aa552633

Unsigned

cmc <hello@cleberg.net> · 2026-08-28 19:28 UTC

Render Org READMEs with the shared OrgSwift package

Depend on OrgSwift (ssh://git@gitbay.org/krz/org-swift.git) and render the .org
README path through OrgRenderer instead of the in-file org renderer. SyntaxHighlighter
conforms to OrgSwift.CodeHighlighter so code blocks keep their Highlightr highlighting;
the sr.ht relative-link resolution is passed through OrgRenderOptions.

Layout: unified · split

Hutch.xcodeproj/project.pbxproj +17
@@ -23,6 +23,7 @@
23 8BE082012F80000100000001 /* HutchWidgetExtension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = 8BE081F62F80000100000001 /* HutchWidgetExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; 23 8BE082012F80000100000001 /* HutchWidgetExtension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = 8BE081F62F80000100000001 /* HutchWidgetExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
24 8BE083012F81000100000001 /* HutchSafariExtension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = 8BE083032F81000100000001 /* HutchSafariExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; 24 8BE083012F81000100000001 /* HutchSafariExtension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = 8BE083032F81000100000001 /* HutchSafariExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
25 8BF100032F9A000100000001 /* Markdown in Frameworks */ = {isa = PBXBuildFile; productRef = 8BF100022F9A000100000001 /* Markdown */; }; 25 8BF100032F9A000100000001 /* Markdown in Frameworks */ = {isa = PBXBuildFile; productRef = 8BF100022F9A000100000001 /* Markdown */; };
26 0F0F0F0F0F0F0F0F000000A3 /* OrgSwift in Frameworks */ = {isa = PBXBuildFile; productRef = 0F0F0F0F0F0F0F0F000000A2 /* OrgSwift */; };
26/* End PBXBuildFile section */ 27/* End PBXBuildFile section */
27 28
28/* Begin PBXContainerItemProxy section */ 29/* Begin PBXContainerItemProxy section */
@@ -174,6 +175,7 @@
174 files = ( 175 files = (
175 8BF100032F9A000100000001 /* Markdown in Frameworks */, 176 8BF100032F9A000100000001 /* Markdown in Frameworks */,
176 8BAA000000000000000000B0 /* Highlightr in Frameworks */, 177 8BAA000000000000000000B0 /* Highlightr in Frameworks */,
178 0F0F0F0F0F0F0F0F000000A3 /* OrgSwift in Frameworks */,
177 ); 179 );
178 runOnlyForDeploymentPostprocessing = 0; 180 runOnlyForDeploymentPostprocessing = 0;
179 }; 181 };
@@ -325,6 +327,7 @@
325 packageProductDependencies = ( 327 packageProductDependencies = (
326 8BF100022F9A000100000001 /* Markdown */, 328 8BF100022F9A000100000001 /* Markdown */,
327 8BAA000000000000000000B2 /* Highlightr */, 329 8BAA000000000000000000B2 /* Highlightr */,
330 0F0F0F0F0F0F0F0F000000A2 /* OrgSwift */,
328 ); 331 );
329 productName = Hutch; 332 productName = Hutch;
330 productReference = 8B4B28D12F6704280045FA19 /* Hutch.app */; 333 productReference = 8B4B28D12F6704280045FA19 /* Hutch.app */;
@@ -426,6 +429,7 @@
426 packageReferences = ( 429 packageReferences = (
427 8BF100012F9A000100000001 /* XCRemoteSwiftPackageReference "swift-markdown" */, 430 8BF100012F9A000100000001 /* XCRemoteSwiftPackageReference "swift-markdown" */,
428 8BAA000000000000000000B3 /* XCRemoteSwiftPackageReference "Highlightr" */, 431 8BAA000000000000000000B3 /* XCRemoteSwiftPackageReference "Highlightr" */,
432 0F0F0F0F0F0F0F0F000000A1 /* XCRemoteSwiftPackageReference "org-swift" */,
429 ); 433 );
430 preferredProjectObjectVersion = 77; 434 preferredProjectObjectVersion = 77;
431 productRefGroup = 8B4B28D22F6704280045FA19 /* Products */; 435 productRefGroup = 8B4B28D22F6704280045FA19 /* Products */;
@@ -1019,6 +1023,14 @@
1019 minimumVersion = 0.8.0; 1023 minimumVersion = 0.8.0;
1020 }; 1024 };
1021 }; 1025 };
1026 0F0F0F0F0F0F0F0F000000A1 /* XCRemoteSwiftPackageReference "org-swift" */ = {
1027 isa = XCRemoteSwiftPackageReference;
1028 repositoryURL = "ssh://git@gitbay.org/krz/org-swift.git";
1029 requirement = {
1030 branch = main;
1031 kind = branch;
1032 };
1033 };
1022/* End XCRemoteSwiftPackageReference section */ 1034/* End XCRemoteSwiftPackageReference section */
1023 1035
1024/* Begin XCSwiftPackageProductDependency section */ 1036/* Begin XCSwiftPackageProductDependency section */
@@ -1032,6 +1044,11 @@
1032 package = 8BF100012F9A000100000001 /* XCRemoteSwiftPackageReference "swift-markdown" */; 1044 package = 8BF100012F9A000100000001 /* XCRemoteSwiftPackageReference "swift-markdown" */;
1033 productName = Markdown; 1045 productName = Markdown;
1034 }; 1046 };
1047 0F0F0F0F0F0F0F0F000000A2 /* OrgSwift */ = {
1048 isa = XCSwiftPackageProductDependency;
1049 package = 0F0F0F0F0F0F0F0F000000A1 /* XCRemoteSwiftPackageReference "org-swift" */;
1050 productName = OrgSwift;
1051 };
1035/* End XCSwiftPackageProductDependency section */ 1052/* End XCSwiftPackageProductDependency section */
1036 }; 1053 };
1037 rootObject = 8B4B28C92F6704280045FA19 /* Project object */; 1054 rootObject = 8B4B28C92F6704280045FA19 /* Project object */;
Hutch.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +10 −1
@@ -1,5 +1,5 @@
1{ 1{
2 "originHash" : "4554417ca2693020116bce7cbda415a5e51ada6b4cc4a8b39f7f43a9644bb5e5", 2 "originHash" : "161ab13c39311c33c8ab987c4e00f5238e1b905e4b929b88f0ff7103a6dc20e4",
3 "pins" : [ 3 "pins" : [
4 { 4 {
5 "identity" : "highlightr", 5 "identity" : "highlightr",
@@ -10,6 +10,15 @@
10 "version" : "2.3.0" 10 "version" : "2.3.0"
11 } 11 }
12 }, 12 },
13 {
14 "identity" : "org-swift",
15 "kind" : "remoteSourceControl",
16 "location" : "ssh://git@gitbay.org/krz/org-swift.git",
17 "state" : {
18 "branch" : "main",
19 "revision" : "47ac630c479b79dbfa8944c91b22b7bb6974cadc"
20 }
21 },
13 { 22 {
14 "identity" : "swift-cmark", 23 "identity" : "swift-cmark",
15 "kind" : "remoteSourceControl", 24 "kind" : "remoteSourceControl",
Hutch/Views/Repositories/ReadmeView.swift +12 −21
@@ -1,3 +1,4 @@
1import OrgSwift
1import SwiftUI 2import SwiftUI
2import WebKit 3import WebKit
3 4
@@ -314,29 +315,19 @@ struct RenderedMarkupContentView: View {
314 return 315 return
315 } 316 }
316 let theme = SyntaxHighlightTheme(colorScheme: colorScheme) 317 let theme = SyntaxHighlightTheme(colorScheme: colorScheme)
318 let host = repositoryHost
319 let owner = ownerCanonicalName
320 let repo = repositoryName
321 let path = readmePath
317 let html = await Task.detached(priority: .userInitiated) { 322 let html = await Task.detached(priority: .userInitiated) {
318 orgToHTML( 323 let options = OrgRenderOptions(
319 text, 324 host: host,
320 codeTheme: theme, 325 owner: owner,
321 imageURLResolver: { source in 326 repositoryName: repo,
322 resolveRepositoryAssetURL( 327 ref: "HEAD",
323 source, 328 readmePath: path
324 owner: ownerCanonicalName,
325 repositoryName: repositoryName,
326 readmePath: readmePath
327 )?
328 .replacingOccurrences(of: "git.sr.ht", with: repositoryHost)
329 },
330 linkURLResolver: { source in
331 resolveRepositoryLinkURL(
332 source,
333 owner: ownerCanonicalName,
334 repositoryName: repositoryName,
335 readmePath: readmePath
336 )?
337 .replacingOccurrences(of: "git.sr.ht", with: repositoryHost)
338 }
339 ) 329 )
330 return OrgRenderer.renderToHTML(text, options: options, highlighter: SyntaxHighlighter(theme: theme))
340 }.value 331 }.value
341 RenderedReadmeHTMLCache.shared.setHTML(html, forKey: cacheKey) 332 RenderedReadmeHTMLCache.shared.setHTML(html, forKey: cacheKey)
342 guard !Task.isCancelled else { return } 333 guard !Task.isCancelled else { return }
Hutch/Views/Repositories/SyntaxHighlighter.swift +7 −1
@@ -1,5 +1,6 @@
1import Foundation 1import Foundation
2import Highlightr 2import Highlightr
3import OrgSwift
3import SwiftUI 4import SwiftUI
4import UIKit 5import UIKit
5 6
@@ -31,7 +32,7 @@ nonisolated enum SyntaxHighlightTheme {
31/// instance must stay on the thread/task that created it. Callers that fail to 32/// instance must stay on the thread/task that created it. Callers that fail to
32/// resolve a language — or hit an unavailable engine — get `nil` and should 33/// resolve a language — or hit an unavailable engine — get `nil` and should
33/// fall back to plain, escaped text. 34/// fall back to plain, escaped text.
34nonisolated final class SyntaxHighlighter { 35nonisolated final class SyntaxHighlighter: CodeHighlighter {
35 private let highlightr: Highlightr? 36 private let highlightr: Highlightr?
36 private let supportedLanguages: Set<String> 37 private let supportedLanguages: Set<String>
37 38
@@ -60,6 +61,11 @@ nonisolated final class SyntaxHighlighter {
60 return Self.html(from: attributed) 61 return Self.html(from: attributed)
61 } 62 }
62 63
64 /// `OrgSwift.CodeHighlighter` conformance — delegates to the existing method.
65 func highlightedHTML(code: String, language: String?) -> String? {
66 highlightedHTML(for: code, language: language)
67 }
68
63 private static let htmlMeasurementFont = UIFont.monospacedSystemFont(ofSize: 12, weight: .regular) 69 private static let htmlMeasurementFont = UIFont.monospacedSystemFont(ofSize: 12, weight: .regular)
64 70
65 private func resolvedLanguage(_ raw: String?) -> String? { 71 private func resolvedLanguage(_ raw: String?) -> String? {