Skip to content
Open
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
2 changes: 2 additions & 0 deletions src-tauri/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions src-tauri/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,7 @@ regex = "1"
walkdir = "2"
tauri-plugin-single-instance = "2"
chrono = "0.4"

[target.'cfg(target_os = "macos")'.dependencies]
objc2 = "0.6"
objc2-foundation = { version = "0.3", features = ["NSUserDefaults", "NSString", "NSDictionary", "NSValue"] }
46 changes: 46 additions & 0 deletions src-tauri/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3632,8 +3632,54 @@ fn handle_cli_args(app: &AppHandle, args: &[String], cwd: &str) -> bool {
opened_preview
}

// On macOS, WKWebView reads per-app preferences from NSUserDefaults to decide
// whether to show the spelling underline and apply auto-correct / smart-substitution
// in contenteditable regions. These keys default to off for new bundle IDs, which
// is why a fresh Tauri app gets neither the red underline nor auto-replace even
// when the HTML `spellcheck`/`autocorrect` attributes are set. Register the
// WebKit defaults so users get Apple-Notes-like behavior on first launch; this
// must happen before the webview is constructed (setting them inside .setup() is
// too late). registerDefaults is used so user-toggled values via the WebKit
// right-click menu still take precedence.
#[cfg(target_os = "macos")]
fn register_webview_defaults() {
use objc2::runtime::AnyObject;
use objc2_foundation::{NSDictionary, NSNumber, NSString, NSUserDefaults};

let keys = [
"WebContinuousSpellCheckingEnabled",
"WebGrammarCheckingEnabled",
"WebAutomaticSpellingCorrectionEnabled",
"WebAutomaticQuoteSubstitutionEnabled",
"WebAutomaticDashSubstitutionEnabled",
"WebAutomaticTextReplacementEnabled",
"WebAutomaticLinkDetectionEnabled",
];
Comment on lines +3649 to +3657
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Trim the registered defaults to the behaviors this PR is actually shipping.

Lines 3653-3656 also enable smart quotes, dash substitution, text replacement, and link detection. That is a broader behavior change than the spellcheck/autocorrect/autocapitalize scope in this PR, and in a markdown editor it can silently rewrite literal text or code-like content. I’d keep this list to the spelling/correction keys unless product explicitly wants the extra substitutions too.

Suggested diff
     let keys = [
         "WebContinuousSpellCheckingEnabled",
         "WebGrammarCheckingEnabled",
         "WebAutomaticSpellingCorrectionEnabled",
-        "WebAutomaticQuoteSubstitutionEnabled",
-        "WebAutomaticDashSubstitutionEnabled",
-        "WebAutomaticTextReplacementEnabled",
-        "WebAutomaticLinkDetectionEnabled",
     ];
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
let keys = [
"WebContinuousSpellCheckingEnabled",
"WebGrammarCheckingEnabled",
"WebAutomaticSpellingCorrectionEnabled",
"WebAutomaticQuoteSubstitutionEnabled",
"WebAutomaticDashSubstitutionEnabled",
"WebAutomaticTextReplacementEnabled",
"WebAutomaticLinkDetectionEnabled",
];
let keys = [
"WebContinuousSpellCheckingEnabled",
"WebGrammarCheckingEnabled",
"WebAutomaticSpellingCorrectionEnabled",
];
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src-tauri/src/lib.rs` around lines 3649 - 3657, The registered defaults array
named keys includes substitution settings beyond spellcheck/autocorrect scope;
trim it to only the spelling/correction-related entries by removing
"WebAutomaticQuoteSubstitutionEnabled", "WebAutomaticDashSubstitutionEnabled",
"WebAutomaticTextReplacementEnabled", and "WebAutomaticLinkDetectionEnabled" so
keys contains only "WebContinuousSpellCheckingEnabled",
"WebGrammarCheckingEnabled", and "WebAutomaticSpellingCorrectionEnabled" (update
the keys array in lib.rs accordingly).


let ns_keys: Vec<_> = keys.iter().map(|k| NSString::from_str(k)).collect();
let key_refs: Vec<&NSString> = ns_keys.iter().map(|k| &**k).collect();

let yes_values: Vec<_> = (0..keys.len()).map(|_| NSNumber::new_bool(true)).collect();
let value_refs: Vec<&AnyObject> = yes_values
.iter()
.map(|v| {
let any: &AnyObject = v;
any
})
.collect();

let dict: objc2::rc::Retained<NSDictionary<NSString, AnyObject>> =
NSDictionary::from_slices(&key_refs, &value_refs);
unsafe {
NSUserDefaults::standardUserDefaults().registerDefaults(&dict);
}
}

#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
#[cfg(target_os = "macos")]
register_webview_defaults();

let app = tauri::Builder::default()
// Single-instance: forward CLI args from subsequent launches to the running instance
.plugin(tauri_plugin_single_instance::init(|app, args, cwd| {
Expand Down
3 changes: 3 additions & 0 deletions src/components/editor/Editor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1132,6 +1132,9 @@ export function Editor({
attributes: {
class:
"prose prose-lg dark:prose-invert max-w-3xl mx-auto focus:outline-none min-h-full px-6 pt-8 pb-24",
spellcheck: "true",
autocorrect: "on",
autocapitalize: "sentences",
},
// Serialize copied text as markdown instead of plain text
clipboardTextSerializer: (slice) => {
Expand Down
Loading