- svelte compilation outputs a separate .css file for each component
- compilation also adds an "import foo.css" to the top of each generated
.mjs file
- when the .mjs files are bundled into app.js, esbuild creates an app.css
as well
- graphs.scss was renamed to graphs_shared.scss and imported in the
top level GraphsPage. Henrik's style refactoring would be a better path
forward, but I needed to make this change for now, as the filenames were
conflicting.
- enable resolver patch on worker binary to ensure js imports work
on subsequent worker requests
- cache ts library content, and use unified interface for cache
- prepare for separate css outputs
Just a quick hack for now to store it in memory, as the temp file
conflicts on Windows due to the lack of a sandbox, and we don't really
have a need to write it to the filesystem anyway.
based on changes from upstream rules_svelte
Their code was using run_node() instead of ctx.actions.run(), which
seems to create a new worker for every CPU core, instead of respecting
the standard limit of 4.
Svelte 3.25.0 and onwards bundle compiler.mjs, which seems to be
preferentially used over the .js file. Presumably this is only breaking
on Windows due to the lack of a sandbox. Resolve by explicitly requesting
the .js file.
This reverts commit 0ca9a6b009.
Unfortunately this is breaking the Windows build. It doesn't seem
to break other platforms, so I'm wondering if maybe it's the Windows
path name or some Windows-specific handling in rules_nodejs that is
to blame:
(08:31:03) ERROR: C:/buildkite-agent/builds/win-ci/ankitects/anki-ci/ts/graphs/BUILD.bazel:21:15:
Svelte ts/graphs/FutureDue.svelte.mjs failed: (Exit 1): bash.exe failed: error executing command C:/msys64/usr/bin/bash.exe -c ... (remaining 1 argument(s) skipped)
Error [ERR_REQUIRE_ESM]: Must use import to load ES Module: C:\bazel\ankici\base\external\build_bazel_rules_svelte_deps\node_modules\svelte\compiler.mjs
at Object.Module._extensions..mjs (internal/modules/cjs/loader.js:1007:9)
at Module.load (internal/modules/cjs/loader.js:812:32)
at Function.Module._load (internal/modules/cjs/loader.js:724:14)
at Module.require (internal/modules/cjs/loader.js:849:19)
at require (internal/modules/cjs/helpers.js:74:18)
at Object.<anonymous> (C:\bazel\ankici\base\external\build_bazel_rules_svelte\internal\svelte.js:10:16)
at Module._compile (internal/modules/cjs/loader.js:956:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:973:10)
at Module.load (internal/modules/cjs/loader.js:812:32)
at Function.Module._load (internal/modules/cjs/loader.js:724:14)
Now behaves the same way as standard find&replace:
- Will match substrings
- Regexs can be used to match multiple items; we no longer split
input on spaces.
- The find&replace dialog has been updated to add tags to the field
list.
We were (ab)using the bulk update routine to do deletions, but that
code was really intended to be used for finding&replacing, where an
exact match is not a requirement.
Qt is pretty enthusiastic about redrawing the card list when any sort
of activity occurs, and by serving blank cells while the DB was busy,
we were getting ugly flashes, and cells getting stuck blank.
Resolve the issue by calculating a row up front and caching it, then
serving stale content when updates are blocked.
- clear_unused_tags() is now undoable, and returns the number of removed
notes
- add a new mw.query_op() helper for immutable queries
- decouple "freeze/unfreeze ui state" hooks from the "interface update
required" hook, so that the former is fired even on error, and can be
made re-entrant
- use a 'block_updates' flag in Python, instead of setUpdatesEnabled(),
as the latter has the side-effect of preventing child windows like
tooltips from appearing, and forces a full redrawn when updates are
enabled again. The new behaviour leads to the card list blanking out
when a long-running op is running, but in the future if we cache the
cell values we can just display them from the cache instead.
- we were indiscriminately saving the note with saveNow(), due to the
call to saveTags(). Changed so that it only saves when the tags field
is focused.
- drain the "on_done" queue on main before launching a new background
task, to lower the chances of something in on_done making a small query
to the DB and hanging until a long op finishes
- the duplicate check in the editor was executed after the webview loads,
leading to it hanging until the sidebar finishes loading. Run it at
set_note() time instead, so that the editor loads first.
- don't throw an error when a long-running op started with with_progress()
finishes after the window it was launched from has closed
- don't throw an error when the browser is closed before the sidebar
has finished loading
Setting it straight away causes the cursor to flash on quick operations,
like saving the current note. Delay it for 300ms, which should hopefully
be long enough to not get in the way, but short enough to give indication
that long-running requests are being processed.
- need to drop cardObjs cache when updating cells
- stop listening on editor_did_* hooks. unfocus_field and typing_timer
are covered by operation_did_execute on note save already, and the
user potentially has editors open in other windows as well
- distinguish between card queue refresh and note text redraw in review
screen again
- update preview window when note updated
- defer setUpdatesEnabled(True) until we receive focus again, as it
causes cells to redraw. We might want to use our own flag to prevent
updating in the model instead of using Qt for this
- Introduced a new transact() method that wraps the return value
in a separate struct that describes the changes that were made.
- Changes are now gathered from the undo log, so we don't need to
guess at what was changed - eg if update_note() is called with identical
note contents, no changes are returned. Card changes will only be set
if cards were actually generated by the update_note() call, and tag
will only be set if a new tag was added.
- mw.perform_op() has been updated to expect the op to return the changes,
or a structure with the changes in it, and it will use them to fire the
change hook, instead of fetching the changes from undo_status(), so there
is no risk of race conditions.
- the various calls to mw.perform_op() have been split into separate
files like card_ops.py. Aside from making the code cleaner, this works
around a rather annoying issue with mypy. Because we run it with
no_strict_optional, mypy is happy to accept an operation that returns None,
despite the type signature saying it requires changes to be returned.
Turning no_strict_optional on for the whole codebase is not practical
at the moment, but we can enable it for individual files.
Still todo:
- The cursor keeps moving back to the start of a field when typing -
we need to ignore the refresh hook when we are the initiator.
- The busy cursor icon should probably be delayed a few hundreds ms.
- Still need to think about a nicer way of handling saveNow()
- op_made_changes(), op_affects_study_queue() might be better embedded
as properties in the object instead
Issues that need fixing:
- when the editor saves the note with perform_op(), if it isn't modified,
no new undo entry is created, and perform_op then returns the changes
made by the previous operation instead
- the approach of fetching the last action in a subsequent backend
method is unsound, as another queued operation may sneak in first before
we have a chance to query the result - it would be better if it were
returned in a single atomic action
- redrawing the current card while editing is likely to make sound
autoplay annoyingly, and it has an unpleasant redraw. We may be better off
fading it out instead
Side note: the editor cursor moves to the start of the field when the
note is updated in another window - it might be nicer to have it move
the cursor to the end instead.