Enforce Rust and Swift ownership boundary

This commit is contained in:
Georg Bauer
2026-07-31 14:10:00 +02:00
parent 6eb27537e8
commit a2615d5d83
10 changed files with 576 additions and 190 deletions

View File

@@ -3,7 +3,6 @@ import MarkdownUI
import QuickLook
import SwiftUI
import UIKit
import UniformTypeIdentifiers
@MainActor
class MarkdownPageViewController: UIViewController {
@@ -273,13 +272,13 @@ final class RepositoryDirectoryViewController: RefreshingTableViewController {
private let path: String
private var rows: [RepositoryContentRow] = []
init(context: AppContext, owner: String, repository: String, path: String) {
init(context: AppContext, owner: String, repository: String, path: String, name: String) {
self.context = context
self.owner = owner
self.repository = repository
self.path = path
super.init()
title = path.split(separator: "/").last.map(String.init) ?? repository
title = name
}
@available(*, unavailable)
@@ -349,18 +348,19 @@ final class RepositoryFileViewController: UIViewController, QLPreviewControllerD
private var loadingTask: Task<Void, Never>?
private var previewURL: URL?
private var markdownSource: String?
private var fileLanguage: String?
private var displayedController: UIViewController?
private var displayedView: UIView?
private weak var sourceScrollView: UIScrollView?
private weak var sourceTextView: UITextView?
init(context: AppContext, owner: String, repository: String, path: String) {
init(context: AppContext, owner: String, repository: String, path: String, name: String) {
self.context = context
self.owner = owner
self.repository = repository
self.path = path
super.init(nibName: nil, bundle: nil)
title = path.split(separator: "/").last.map(String.init)
title = name
}
@available(*, unavailable)
@@ -372,19 +372,17 @@ final class RepositoryFileViewController: UIViewController, QLPreviewControllerD
beginNavigationLoading(spinner)
loadingTask = Task {
do {
let data = try await context.core.repositoryFile(
let page = try await context.core.repositoryFile(
owner: owner,
repository: repository,
path: path
)
if !isMediaFile(path), let source = String(data: data, encoding: .utf8) {
if isMarkdownFile {
showMarkdown(source)
} else {
showSource(source)
}
} else {
try showQuickLook(data)
title = page.name
fileLanguage = page.language.isEmpty ? nil : page.language
switch page.kind {
case "markdown": showMarkdown(page.text)
case "source": showSource(page.text)
default: try showQuickLook(page.data, name: page.name)
}
} catch {
if !Task.isCancelled { show(error: error) }
@@ -398,20 +396,6 @@ final class RepositoryFileViewController: UIViewController, QLPreviewControllerD
updateSourceLayout()
}
private func isMediaFile(_ path: String) -> Bool {
guard let type = UTType(filenameExtension: (path as NSString).pathExtension) else {
return false
}
return type.conforms(to: .image)
|| type.conforms(to: .audio)
|| type.conforms(to: .audiovisualContent)
|| type.conforms(to: .pdf)
}
private var isMarkdownFile: Bool {
["md", "markdown", "mdown", "mkd"].contains((path as NSString).pathExtension.lowercased())
}
deinit {
loadingTask?.cancel()
if let previewURL { try? FileManager.default.removeItem(at: previewURL) }
@@ -464,7 +448,7 @@ final class RepositoryFileViewController: UIViewController, QLPreviewControllerD
traitCollection.userInterfaceStyle == .dark ? "atom-one-dark" : "atom-one-light"
)
highlighter?.theme.setCodeFont(.monospacedSystemFont(ofSize: 13, weight: .regular))
let highlighted = highlighter?.highlight(source, as: sourceLanguage(path))
let highlighted = highlighter?.highlight(source, as: fileLanguage)
?? NSAttributedString(string: source, attributes: [
.font: UIFont.monospacedSystemFont(ofSize: 13, weight: .regular),
.foregroundColor: UIColor.label,
@@ -532,8 +516,7 @@ final class RepositoryFileViewController: UIViewController, QLPreviewControllerD
scrollView.contentSize = contentSize
}
private func showQuickLook(_ data: Data) throws {
let name = path.split(separator: "/").last.map(String.init) ?? "Preview"
private func showQuickLook(_ data: Data, name: String) throws {
let url = FileManager.default.temporaryDirectory
.appendingPathComponent("\(UUID().uuidString)-\(name)")
try data.write(to: url, options: .atomic)