|
1 | 1 | <script lang="ts"> |
2 | 2 | import type { LanguageSupport } from "@codemirror/language"; |
3 | 3 | import type { EditorView } from "@codemirror/view"; |
4 | | - import { onMount } from "svelte"; |
| 4 | + import { onMount, untrack } from "svelte"; |
5 | 5 |
|
6 | 6 | import { get, put } from "../../api"; |
7 | 7 | import type { SourceFile } from "../../api/validators"; |
|
19 | 19 | import { searchParams } from "../../stores/url"; |
20 | 20 | import EditorMenu from "./EditorMenu.svelte"; |
21 | 21 |
|
22 | | - export let source: SourceFile; |
23 | | - export let beancount_language_support: LanguageSupport; |
| 22 | + interface Props { |
| 23 | + source: SourceFile; |
| 24 | + beancount_language_support: LanguageSupport; |
| 25 | + } |
| 26 | +
|
| 27 | + let { source, beancount_language_support }: Props = $props(); |
24 | 28 |
|
25 | | - $: file_path = source.file_path; |
| 29 | + let file_path = $derived(source.file_path); |
26 | 30 |
|
27 | | - let changed = false; |
| 31 | + let changed = $state(false); |
28 | 32 | const onDocChanges = () => { |
29 | 33 | changed = true; |
30 | 34 | }; |
31 | 35 |
|
32 | | - let sha256sum = ""; |
33 | | - let saving = false; |
| 36 | + let sha256sum = $state(""); |
| 37 | + let saving = $state(false); |
34 | 38 |
|
35 | 39 | /** |
36 | 40 | * Save the contents of the editor. |
|
73 | 77 | beancount_language_support, |
74 | 78 | ); |
75 | 79 |
|
76 | | - // update editor contents if source changes |
77 | | - // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions, @typescript-eslint/no-unnecessary-condition |
78 | | - $: if (source) { |
79 | | - editor.dispatch(replaceContents(editor.state, source.source)); |
80 | | - sha256sum = source.sha256sum; |
81 | | - editor.focus(); |
82 | | - changed = false; |
83 | | - } |
84 | | -
|
85 | | - // wrap this in a function to not trigger the reactive block below |
86 | | - // on store updates. |
87 | | - function jumpToInsertOption() { |
88 | | - const opts = $fava_options.insert_entry.filter( |
89 | | - (f) => f.filename === file_path, |
90 | | - ); |
91 | | - const line = parseInt($searchParams.get("line") ?? "0", 10); |
92 | | - const last_insert_opt = opts[opts.length - 1]; |
93 | | - const lineToScrollTo = (() => { |
| 80 | + $effect(() => { |
| 81 | + // update editor contents if source changes |
| 82 | + // eslint-disable-next-line @typescript-eslint/no-unused-expressions |
| 83 | + source; |
| 84 | + untrack(() => { |
| 85 | + editor.dispatch(replaceContents(editor.state, source.source)); |
| 86 | + sha256sum = source.sha256sum; |
| 87 | + editor.focus(); |
| 88 | + changed = false; |
| 89 | + }); |
| 90 | + }); |
| 91 | +
|
| 92 | + $effect(() => { |
| 93 | + // Go to line if the edited file changes. |
| 94 | + // eslint-disable-next-line @typescript-eslint/no-unused-expressions |
| 95 | + file_path; |
| 96 | + untrack(() => { |
| 97 | + const opts = $fava_options.insert_entry.filter( |
| 98 | + (f) => f.filename === file_path, |
| 99 | + ); |
| 100 | + const last_insert_opt = opts[opts.length - 1]; |
| 101 | + const line = parseInt($searchParams.get("line") ?? "0", 10); |
| 102 | + let line_to_scroll_to = null; |
94 | 103 | if (line > 0) { |
95 | | - return line; |
| 104 | + line_to_scroll_to = line; |
| 105 | + } else if (last_insert_opt) { |
| 106 | + line_to_scroll_to = last_insert_opt.lineno - 1; |
96 | 107 | } |
97 | | - if (last_insert_opt) { |
98 | | - return last_insert_opt.lineno - 1; |
99 | | - } |
100 | | - return editor.state.doc.lines; |
101 | | - })(); |
102 | | - editor.dispatch(scrollToLine(editor.state, lineToScrollTo)); |
103 | | - } |
104 | | -
|
105 | | - // Go to line if the edited file changes. |
106 | | - $: if (file_path) { |
107 | | - jumpToInsertOption(); |
108 | | - } |
109 | | -
|
110 | | - // Update diagnostics, showing errors in the editor |
111 | | - $: { |
| 108 | + editor.dispatch( |
| 109 | + scrollToLine(editor.state, line_to_scroll_to ?? editor.state.doc.lines), |
| 110 | + ); |
| 111 | + }); |
| 112 | + }); |
| 113 | +
|
| 114 | + $effect(() => { |
| 115 | + // Update diagnostics, showing errors in the editor |
112 | 116 | // Only show errors for this file, or general errors (AKA no source) |
113 | 117 | const errorsForFile = $errors.filter( |
114 | 118 | (err) => err.source === null || err.source.filename === file_path, |
115 | 119 | ); |
116 | 120 | editor.dispatch(setErrors(editor.state, errorsForFile)); |
117 | | - } |
| 121 | + }); |
118 | 122 |
|
119 | 123 | const checkEditorChanges = () => |
120 | 124 | changed |
|
126 | 130 |
|
127 | 131 | <form |
128 | 132 | class="fixed-fullsize-container" |
129 | | - on:submit|preventDefault={async () => save(editor)} |
| 133 | + onsubmit={async (event) => { |
| 134 | + event.preventDefault(); |
| 135 | + return save(editor); |
| 136 | + }} |
130 | 137 | > |
131 | 138 | <EditorMenu {file_path} {editor}> |
132 | 139 | <SaveButton {changed} {saving} /> |
|
0 commit comments