Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
`MarkdownEditorConfiguration.safeAreaInsets`.

### Fixed
- `NativeTextViewWrapper` keeps links clickable and text selectable
when `isEditable: false`; `isSelectable` is no longer coupled to
`isEditable`. (#31)
- `NativeTextViewWrapper` now applies its initial styling pass even when
the bound text starts at its final value (e.g. supplied as a SwiftUI
`@State` initializer). Previously the editor would render the raw
Expand Down
7 changes: 6 additions & 1 deletion Sources/MarkdownEngine/Parser/MarkdownDetection.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,13 @@ enum MarkdownDetection {
static func computeActiveTokenIndices(
selectionRange: NSRange,
tokens: [MarkdownToken],
in text: NSString
in text: NSString,
suppressed: Bool = false
) -> Set<Int> {
// In read-only mode (no caret) we never want to reveal raw markdown
// syntax — `isEditable: false` should hide all tokens regardless of
// the trailing selection NSTextView keeps around after a click.
if suppressed { return [] }
var indices: Set<Int> = []
let caretLocation = selectionRange.location
for (index, token) in tokens.enumerated() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,15 @@ extension NativeTextViewCoordinator {
textView.textStorage?.setAttributes(baseAttrs, range: fullRange)

let tokens = parsedDocument(for: displayText).tokens
let caretLocation = textView.selectedRange().location
// Hide the caret position from styling when the view is read-only,
// otherwise clicks reveal raw token syntax (#, `, etc.) even though
// the user can't edit.
let caretLocation = textView.isEditable ? textView.selectedRange().location : -1
activeTokenIndices = MarkdownDetection.computeActiveTokenIndices(
selectionRange: textView.selectedRange(),
tokens: tokens,
in: nsDisplay
in: nsDisplay,
suppressed: !textView.isEditable
)

let ranges = MarkdownStyler.styleAttributes(
Expand Down Expand Up @@ -102,7 +106,7 @@ extension NativeTextViewCoordinator {
paragraphCandidates: paragraphCandidates,
baseFont: baseFont,
paragraphStyle: paragraphStyle,
caretLocation: textView.selectedRange().location,
caretLocation: textView.isEditable ? textView.selectedRange().location : -1,
activeTokenIndices: activeTokenIndices,
wikiLinkIDProvider: { [weak self] range in
self?.wikiLinkID(for: range)
Expand Down Expand Up @@ -217,7 +221,8 @@ extension NativeTextViewCoordinator {
activeTokenIndices = MarkdownDetection.computeActiveTokenIndices(
selectionRange: textView.selectedRange(),
tokens: tokens,
in: nsText
in: nsText,
suppressed: !textView.isEditable
)
restyleTextView(textView, paragraphCandidates: paragraphs, tokens: tokens)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,8 @@ extension NativeTextViewCoordinator {
activeTokenIndices = MarkdownDetection.computeActiveTokenIndices(
selectionRange: safeSelRange,
tokens: tokens,
in: fullText
in: fullText,
suppressed: !tv.isEditable
)
filterImageEmbedActiveTokens(parsed: parsed, text: fullText, selectionLocation: safeSelRange.location)
updateAutocorrectSettings(
Expand Down Expand Up @@ -182,7 +183,7 @@ extension NativeTextViewCoordinator {
let nsText = tv.string as NSString

let prevActive = activeTokenIndices
activeTokenIndices = MarkdownDetection.computeActiveTokenIndices(selectionRange: selRange, tokens: tokens, in: nsText)
activeTokenIndices = MarkdownDetection.computeActiveTokenIndices(selectionRange: selRange, tokens: tokens, in: nsText, suppressed: !tv.isEditable)
filterImageEmbedActiveTokens(parsed: parsed, text: nsText, selectionLocation: selRange.location)
updateAutocorrectSettings(
tv,
Expand Down Expand Up @@ -323,7 +324,8 @@ extension NativeTextViewCoordinator {
pendingPreEditActiveTokenIndices = MarkdownDetection.computeActiveTokenIndices(
selectionRange: textView.selectedRange(),
tokens: parsed.tokens,
in: textView.string as NSString
in: textView.string as NSString,
suppressed: !textView.isEditable
)

// Block LaTeX auto-wrap: insert newlines to keep $$ on its own line
Expand Down
4 changes: 2 additions & 2 deletions Sources/MarkdownEngine/TextView/NativeTextViewWrapper.swift
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ public struct NativeTextViewWrapper: NSViewRepresentable {
context.coordinator.configuration = configuration
textView.insertionPointColor = configuration.theme.bodyText
textView.isEditable = isEditable
textView.isSelectable = isEditable
textView.isSelectable = true
textView.isRichText = true
let initialState = WikiLinkService.makeDisplayState(from: text)
textView.string = initialState.display
Expand Down Expand Up @@ -264,7 +264,7 @@ public struct NativeTextViewWrapper: NSViewRepresentable {
(nsView.documentView as? NativeTextView)?.configuration.services = configuration.services
}
textView.isEditable = isEditable
textView.isSelectable = isEditable
textView.isSelectable = true
textView.insertionPointColor = isEditable ? context.coordinator.configuration.theme.bodyText : .clear
let fontChanged = (context.coordinator.fontName != fontName) || (context.coordinator.fontSize != fontSize)
if let pendingInlineReplacement {
Expand Down
Loading