Troubleshooting & Debugging
Relevant source files
The following files were used as context for generating this wiki page:
This page details the error handling mechanisms, state validation, and debugging patterns implemented in the Writer project. It focuses on how the application manages failures in file system access, data persistence, and document exporting to maintain a distraction-free user experience.
The core of the troubleshooting architecture relies on the @Observable state management system, primarily through the EditorStore, which captures and surfaces errors to the UI layer.
Error Handling Architecture
Writer utilizes a centralized error reporting system where the EditorStore maintains an optional errorMessage string. When operations such as file loading, saving, or renaming fail, the store catches the exception and updates this property, which is subsequently observed by the ContentView and displayed in the sidebar overlay.
The flow above illustrates how file operations interact with the error state.
Sources: EditorStore.swift:42, ContentView.swift:130-137
Key Error States and Descriptions
| Component | Error Property | Purpose |
|---|---|---|
EditorStore | errorMessage | Holds the last recorded file system or state error for UI display. |
WriterApp | exportError | Specifically captures failures during HTML, PDF, or RTF export processes. |
ExportError | enum cases | Defines specific export failures: .cancelled and .writeFailed(Error). |
Sources: EditorStore.swift:42, WriterApp.swift:15, HTMLExporter.swift:44-55
File System & Security Scoping
Debugging file access issues often involves verifying the "Security-Scoped Bookmarks." Writer uses these to persist folder access across app launches. If a folder is moved or permissions change, the bookmark may become "stale."
Bookmark Resolution Flow
The application automatically attempts to refresh stale bookmarks to prevent silent access failures.
Sources: EditorStore.swift:165-189, CLAUDE.md:37-40
Common File Failures
- Missing Root: If
rootURLis nil, the app defaults to an error state requesting folder selection. Sources: EditorStore.swift:192-200 - File Deletion: When a file is deleted from the disk externally,
refreshFiles()validates its existence. If the currently selected file is missing, the store resetsselectedFileURLanddocumentText. Sources: EditorStore.swift:204-211
Export Troubleshooting
The export system (HTML, PDF, RTF) runs within Task blocks in WriterApp. Debugging export failures involves checking the exportError state, which triggers a SwiftUI alert.
Export Error Logic
do {
let url = try await exporter.save(suggestedName: suggestedName)
exportSuccess = url.path
} catch let error as any Error where (error as NSError).code != NSUserCancelledError {
exportError = error.localizedDescription
}
Citations: WriterApp.swift:24-28
The application explicitly ignores NSUserCancelledError (code 3072) to avoid showing error alerts when a user simply closes the Save Panel without saving.
Sources: WriterApp.swift:26, HTMLExporter.swift:34-36
UI & Syntax Highlighting Debugging
The MarkdownTextViewInternal handles syntax highlighting via NSRegularExpression. Troubleshooting rendering issues requires examining the applyMarkdownStyling() method.
Syntax Processing Sequence
- Clear Attributes: Remove all previous styling from the
NSTextStorage. - Base Attributes: Apply system monospaced font and paragraph styles.
- Regex Matching: Sequentially apply Heading, Bold, Italic, and Highlight styles.
- Typing Attributes: Reset
typingAttributesto ensure new text follows base styling rather than inheriting from the previous character's markdown style.
Sources: MarkdownTextView.swift:116-147
Regex Constants
Debugging matching behavior starts with the following internal patterns:
- Headings:
^#{1,6}\s.*$ - Bold:
(\*\\*|__)(?=[^\\s*_\\n])(.+?)(?<=[^\\s*_\\n])\\1 - Highlights:
==(?=[^\\s=\\n])(.+?)(?<=[^\\s=\\n])==
Sources: MarkdownTextView.swift:85-102
Summary
Troubleshooting in Writer is primarily driven by observing the EditorStore's state. Developers should look to the errorMessage for file-system issues and the WriterApp.exportError for conversion failures. The architecture ensures that errors are caught at the point of failure (IO or Rendering) and propagated to the UI through the Observation framework.