diff --git a/scripts/reloadOpenToolbar.test.ts b/scripts/reloadOpenToolbar.test.ts index b783065..194660d 100644 --- a/scripts/reloadOpenToolbar.test.ts +++ b/scripts/reloadOpenToolbar.test.ts @@ -24,10 +24,10 @@ test('preview-level open shortcut handles Ctrl/Cmd+O outside Monaco without doub assert.match(markdownViewer, /cmdOrCtrl[\s\S]*key === 'o'[\s\S]*selectFile\(\)/); }); -test('editor toolbar delegates to Monaco actions and exposes expected Markdown commands', () => { +test('editor toolbar forwards Monaco actions and optional payloads', () => { assert.match(markdownViewer, /import EditorToolbar from '\.\/components\/EditorToolbar\.svelte'/); - assert.match(markdownViewer, / editorPane\?\.runEditorAction\(actionId\)\}/); - assert.match(editor, /export function runEditorAction\(actionId: string\)/); + assert.match(markdownViewer, / editorPane\?\.runEditorAction\(actionId, payload\)\}/); + assert.match(editor, /export function runEditorAction\(actionId: string, payload\?: any\)/); for (const actionId of [ 'fmt-bold', diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index 99ce9cd..2347d30 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -275,6 +275,22 @@ mod tests { assert!(out.contains("(content: &'a str) -> Cow<'a, str> { processed } +fn process_parenthesized_autolinks(content: &str) -> Cow<'_, str> { + let regions = code_region_ranges(content); + let mut output = String::new(); + let mut copied_to = 0; + let mut scan_from = 0; + + while let Some(opening_offset) = content[scan_from..].find('(') { + let opening = scan_from + opening_offset; + let url_start = opening + 1; + let url_tail = &content[url_start..]; + if !(url_tail.starts_with("http://") + || url_tail.starts_with("https://") + || url_tail.starts_with("ftp://")) + { + scan_from = url_start; + continue; + } + + let mut depth = 1usize; + let mut closing = None; + for (offset, ch) in url_tail.char_indices() { + if ch.is_whitespace() { + break; + } + match ch { + '(' => depth += 1, + ')' => { + depth -= 1; + if depth == 0 { + closing = Some(url_start + offset); + break; + } + } + _ => {} + } + } + + let Some(closing) = closing else { + scan_from = url_start; + continue; + }; + let after_closing = closing + ')'.len_utf8(); + let adjacent_text = content[after_closing..] + .chars() + .next() + .is_some_and(char::is_alphanumeric); + if !adjacent_text || in_code_region(®ions, opening) { + scan_from = after_closing; + continue; + } + + let url = &content[url_start..closing]; + output.push_str(&content[copied_to..url_start]); + output.push('['); + output.push_str(url); + output.push_str("]("); + output.push_str(url); + output.push_str(")"); + output.push(')'); + copied_to = after_closing; + scan_from = after_closing; + } + + if output.is_empty() { + Cow::Borrowed(content) + } else { + output.push_str(&content[copied_to..]); + Cow::Owned(output) + } +} + #[tauri::command] fn convert_markdown(content: &str) -> String { - let processed_embeds = process_internal_embeds(content); + let processed_autolinks = process_parenthesized_autolinks(content); + let processed_embeds = process_internal_embeds(&processed_autolinks); let processed_links = process_wikilinks(&processed_embeds); let mut options = ComrakOptions { diff --git a/src/lib/components/Settings.svelte b/src/lib/components/Settings.svelte index f1b8d7d..15d8673 100644 --- a/src/lib/components/Settings.svelte +++ b/src/lib/components/Settings.svelte @@ -1172,9 +1172,13 @@

{t('settings.toolbarsSettings', settings.language)}

-
-
-

{t('settings.applicationToolbar', settings.language)}

+
+ + + {t('settings.applicationToolbar', settings.language)} + +
+
{/each} +
-
- -
-
-

{t('settings.editorToolbar', settings.language)}

+ + +
+ + + {t('settings.editorToolbar', settings.language)} + +
+
{/each} +
-
+ {:else if activeCategory === 'files'}
@@ -1712,10 +1722,21 @@ display: none; } - .toolbar-section { - display: flex; - flex-direction: column; - gap: 8px; + .toolbar-settings-chevron { + width: 7px; + height: 7px; + border-right: 1.5px solid var(--color-fg-muted); + border-bottom: 1.5px solid var(--color-fg-muted); + transform: rotate(-45deg); + transition: transform 0.12s ease; + } + + .toolbar-settings[open] .toolbar-settings-chevron { + transform: rotate(45deg); + } + + .toolbar-settings-body { + padding-bottom: 12px; } .toolbar-section-header { @@ -1725,15 +1746,6 @@ padding-bottom: 2px; } - .toolbar-section-header h3 { - margin: 0; - font-size: 12px; - font-weight: 600; - color: var(--color-fg-muted); - text-transform: uppercase; - letter-spacing: 0.5px; - } - .toolbar-settings-list { display: flex; flex-direction: column;