feat: add persistent Markdown notes
This commit is contained in:
@@ -0,0 +1,74 @@
|
||||
import AppKit
|
||||
|
||||
public struct Note: Identifiable {
|
||||
public let id: UUID
|
||||
public let contents: NSAttributedString
|
||||
public let title: String
|
||||
|
||||
init(id: UUID, contents: NSAttributedString) {
|
||||
self.id = id
|
||||
self.contents = NSAttributedString(attributedString: contents)
|
||||
var title = "Untitled Note"
|
||||
contents.string.enumerateLines { line, stop in
|
||||
let trimmed = line.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
if !trimmed.isEmpty {
|
||||
title = String(trimmed.prefix(60))
|
||||
stop = true
|
||||
}
|
||||
}
|
||||
self.title = title
|
||||
}
|
||||
}
|
||||
|
||||
@MainActor
|
||||
public final class NotesStore {
|
||||
public private(set) var notes: [Note] = []
|
||||
private let directory: URL
|
||||
|
||||
public init(directory: URL = FileManager.default.urls(
|
||||
for: .applicationSupportDirectory, in: .userDomainMask
|
||||
)[0].appendingPathComponent("Conjure/Notes", isDirectory: true)) throws {
|
||||
self.directory = directory
|
||||
try FileManager.default.createDirectory(at: directory, withIntermediateDirectories: true)
|
||||
let files = try FileManager.default.contentsOfDirectory(
|
||||
at: directory, includingPropertiesForKeys: nil
|
||||
).filter { $0.pathExtension.lowercased() == "rtfd" }
|
||||
.sorted { $0.lastPathComponent < $1.lastPathComponent }
|
||||
notes = try files.map { url in
|
||||
guard let id = UUID(uuidString: url.deletingPathExtension().lastPathComponent) else {
|
||||
throw CocoaError(.fileReadCorruptFile)
|
||||
}
|
||||
let contents = try NSAttributedString(
|
||||
url: url, options: [.documentType: NSAttributedString.DocumentType.rtfd],
|
||||
documentAttributes: nil
|
||||
)
|
||||
return Note(id: id, contents: contents)
|
||||
}
|
||||
}
|
||||
|
||||
public func create() throws -> UUID {
|
||||
let note = Note(id: UUID(), contents: NSAttributedString(string: ""))
|
||||
try save(note)
|
||||
notes.append(note)
|
||||
notes.sort { $0.id.uuidString < $1.id.uuidString }
|
||||
return note.id
|
||||
}
|
||||
|
||||
public func update(id: UUID, contents: NSAttributedString) throws {
|
||||
guard let index = notes.firstIndex(where: { $0.id == id }) else {
|
||||
throw CocoaError(.fileNoSuchFile)
|
||||
}
|
||||
let note = Note(id: id, contents: contents)
|
||||
try save(note)
|
||||
notes[index] = note
|
||||
}
|
||||
|
||||
private func save(_ note: Note) throws {
|
||||
let wrapper = try note.contents.fileWrapper(
|
||||
from: NSRange(location: 0, length: note.contents.length),
|
||||
documentAttributes: [.documentType: NSAttributedString.DocumentType.rtfd]
|
||||
)
|
||||
let url = directory.appendingPathComponent(note.id.uuidString + ".rtfd", isDirectory: true)
|
||||
try wrapper.write(to: url, options: .atomic, originalContentsURL: url)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user