Description
When clicking a relative markdown link that uses .. to navigate to a parent directory, the link fails to open the file.
For example, given this file structure:
project/
├── docs/
│ └── notes.md ← editing this file
└── assets/
└── diagram.pdf
A link in notes.md like [Diagram](../assets/diagram.pdf) should open project/assets/diagram.pdf, but it fails silently.
Links within the same directory (e.g., [Other](other.md)) work correctly.
Root Cause
In EditorViewController+Delegate.swift (lines 16-42), the createWebViewWith delegate handles link clicks from the WKWebView:
- The preview WebView has
baseURL = http://localhost/
- A relative link like
../assets/diagram.pdf is resolved by WKWebView against http://localhost/, producing http://localhost/assets/diagram.pdf (the .. is consumed since you can't go above the URL root)
- The string replacement then swaps
http://localhost/ with document.baseURL (e.g., file:///project/docs/)
- Result:
file:///project/docs/assets/diagram.pdf — which is wrong. It should be file:///project/assets/diagram.pdf
The .. component is lost during step 2 because HTTP URL resolution normalizes it away before the string substitution in step 3 can preserve it.
Suggested Fix
Resolve the relative path against document.baseURL directly instead of relying on string replacement of the WKWebView's localhost URL. For example:
func webView(_ webView: WKWebView, createWebViewWith configuration: WKWebViewConfiguration, for navigationAction: WKNavigationAction, windowFeatures: WKWindowFeatures) -> WKWebView? {
guard let url = navigationAction.request.url else {
return nil
}
let resolvedURL: URL? = {
// If it already has a file scheme or other real scheme, use directly
if url.scheme != "http" || url.host != "localhost" {
return url
}
// Resolve the original relative path against the document's base URL
guard let baseURL = document?.baseURL else { return nil }
let relativePath = url.path.removingPercentEncoding ?? url.path
return baseURL.appending(path: relativePath).standardized
}()
if let resolvedURL {
NSWorkspace.shared.openOrReveal(url: resolvedURL)
}
return nil
}
The key addition is .standardized which resolves .. components in the path.
Workaround
Create a symlink in the subdirectory pointing to the parent, allowing forward-only relative paths that avoid ...
Description
When clicking a relative markdown link that uses
..to navigate to a parent directory, the link fails to open the file.For example, given this file structure:
A link in
notes.mdlike[Diagram](../assets/diagram.pdf)should openproject/assets/diagram.pdf, but it fails silently.Links within the same directory (e.g.,
[Other](other.md)) work correctly.Root Cause
In
EditorViewController+Delegate.swift(lines 16-42), thecreateWebViewWithdelegate handles link clicks from the WKWebView:baseURL = http://localhost/../assets/diagram.pdfis resolved by WKWebView againsthttp://localhost/, producinghttp://localhost/assets/diagram.pdf(the..is consumed since you can't go above the URL root)http://localhost/withdocument.baseURL(e.g.,file:///project/docs/)file:///project/docs/assets/diagram.pdf— which is wrong. It should befile:///project/assets/diagram.pdfThe
..component is lost during step 2 because HTTP URL resolution normalizes it away before the string substitution in step 3 can preserve it.Suggested Fix
Resolve the relative path against
document.baseURLdirectly instead of relying on string replacement of the WKWebView's localhost URL. For example:The key addition is
.standardizedwhich resolves..components in the path.Workaround
Create a symlink in the subdirectory pointing to the parent, allowing forward-only relative paths that avoid
...