Commit Graph

1625 Commits

Author SHA1 Message Date
Damien Elmes
0eddb25287
Integrate AnkiDroid's backend patches into the repo (#2290)
* Relax chrono specification for AnkiDroid

https://github.com/ankidroid/Anki-Android-Backend/pull/251

* Add AnkiDroid service and AnkiDroid customizations

Most of the work here was done by David in the Backend repo; integrating
it into this repo for ease of future maintenance.

Based on 5d9f262f4c
with some tweaks:

- Protobuf imports have been fixed to match the recent refactor
- FatalError has been renamed to AnkidroidPanicError
- Tweaks to the desktop code to deal with the extra arg to open_collection,
and exclude AnkiDroid service methods from our Python code.

* Refactor AnkiDroid's DB code to avoid uses of unsafe
2023-01-03 13:11:23 +10:00
Damien Elmes
4c5a2461d0 Handle broken utimes() on Android
Closes https://github.com/ankidroid/Anki-Android/issues/12827
Closes https://github.com/ankidroid/Anki-Android/issues/12974
2022-12-28 16:33:06 +10:00
Damien Elmes
a38121a713 Add Debug impl for Collection 2022-12-24 10:44:41 +10:00
Damien Elmes
a82f8d6872 Remove unused before_upload method 2022-12-24 10:44:41 +10:00
Damien Elmes
0570cfdf48 Migrate from slog to tracing
The Rust community appear to have converged on tracing - it's used by
the Rust compiler, and receives close to 10x the number of downloads
that slog does. Its API is more ergonomic, and it does a much nicer
job with async rust.

To make this change, we no longer pass around explicit loggers, and rely
on a globally-registered one. The log file location has been changed
from one in each profile folder to a single one in the base folder. This
will remain empty for most users, since only errors are logged by default,
but may be useful for debugging future changes.
2022-12-24 10:44:40 +10:00
Damien Elmes
d294fff882 Simplify solution for #2279 2022-12-19 18:13:34 +10:00
Damien Elmes
67acaa17e4 Fix panic when adding non-Latin text to fields
Closes #2279
2022-12-19 18:02:43 +10:00
TRIAEIOU
9901ae428a
Nested clozes and increased cloze meta data (#2141)
* Nested clozes and increased cloze meta data

* Update contributors

* This reverts commit 3423df73f89f04a606b1bff3542a68a49ca52e9f.

* Update CONTRIBUTORS

* Formating

* Formating

* Formating

* Formating

* Formating

* Formating

* Formating

* Formating

* Code refactor

* Formating

* Formating

* Formating

* Formating and dead code

* Correct test case

* Remove Hint and Close storage of token string

* Update

* Formating

* Formating

* Formating

* Use write! instead of .push_str(&format).

* Formating
2022-12-19 12:03:15 +10:00
Damien Elmes
0555f4898c Update crate name in docstrings to fix 'cargo test' 2022-12-16 22:30:54 +10:00
Damien Elmes
37151213cd Move more of the graph processing into the backend
The existing architecture serializes all cards and revlog entries in
the search range into a protobuf message, which the web frontend needs
to decode and then process. The thinking at the time was that this would
make it easier for add-ons to add extra graphs, but in the ~2.5 years
since the new graphs were introduced, no add-ons appear to have taken
advantage of it.

The cards and revlog entries can grow quite large on large collections -
on a collection I tested with approximately 2.5M reviews, the serialized
data is about 110MB, which is a lot to have to deserialize in JavaScript.

This commit shifts the preliminary processing of the data to the Rust end,
which means the data is able to be processed faster, and less needs to
be sent to the frontend. On the test collection above, this reduces the
serialized data from about 110MB to about 160KB, resulting in a more
than 2x performance improvement, and reducing frontend memory usage from
about 400MB to about 40MB.

This also makes #2043 more feasible - while it is still about 50-100%
slower than protobufjs, with the much smaller message size, the difference
is only about 10ms.
2022-12-16 21:42:17 +10:00
Damien Elmes
fa625d7ad8
Minor Rust cleanups (#2272)
* Run cargo +nightly fmt

* Latest prost-build includes clippy workaround

* Tweak Rust protobuf imports

- Avoid use of stringify!(), as JetBrains editors get confused by it
- Stop merging all protobuf symbols into a single namespace

* Remove some unnecessary qualifications

Found via IntelliJ lint

* Migrate some asserts to assert_eq/ne

* Remove mention of node_modules exclusion

This no longer seems to be necessary after migrating away from Bazel,
and excluding it means TS/Svelte files can't be edited properly.
2022-12-16 21:40:27 +10:00
Damien Elmes
22ecef6fb2
Merge pull request #2255 from RumovZ/replace-pct-str-2
Replace pct-str with local percent_encoding crate
2022-12-16 11:21:04 +00:00
Damien Elmes
35cbde65d7 Revert "Always scan for media changes"
This reverts commit 09cb8b3cf6.

Overhead on larger folders/slower devices is more than I originally
anticipated, and can run into multiple seconds. This seems to be
particularly egregious on mobile, which I presume is due to sandboxing
overhead.
2022-12-15 20:40:20 +10:00
Damien Elmes
86b52f7626 Add a small unit test
pct-str encoded the / character as well, but the difference shouldn't
matter in our case.
2022-12-12 14:54:11 +10:00
RumovZ
c888ccc285 Replace pct-str with local ascii_percent_encoding 2022-12-09 11:49:39 +01:00
RumovZ
0b206b8a81 Ignore non-ASCII chars in ascii_percent_encoding 2022-12-09 11:47:59 +01:00
RumovZ
55f27779cf Add local copy of percent_encoding crate 2022-12-09 11:46:00 +01:00
RumovZ
0e7f02bfb7
Update Chrono Crate (#2242)
* Remove deprecated `and_hms()`

* Update chrono

* Update licenses and fix script

* Remove deprecated Date struct

* Remove chrono pin

* Skip format check on .vscode

Was failing for no reason.

* Replace deprecated chrono functions

* Add cargo-deny to update-licenses & pin versions (dae)

* Remove time 0.1 dependency  (dae)

We don't need to wait for chrono 0.5; it was provided behind a legacy
feature flag.
2022-12-07 17:00:14 +10:00
Damien Elmes
7e3ac53869 Allow unit tests to pass even when Qt translations overridden 2022-12-04 14:25:54 +10:00
RumovZ
90a3bbfdb8
Cap calculated hard delay secs at again delay + 1d (#2229) 2022-12-03 18:54:40 +10:00
Damien Elmes
e3167c4e3c Update incompatible crates 2022-11-30 12:38:10 +10:00
Damien Elmes
b4f4df0030 Pin chrono; update compatible Rust crates
Also pin reqwest in our other crates
2022-11-30 12:38:10 +10:00
Damien Elmes
0ac7969e2a Use workspace package info in more crates; mark private for cargo-deny 2022-11-30 12:19:56 +10:00
Damien Elmes
e497a56f54 Re-enable formatting for .toml files 2022-11-28 09:16:28 +10:00
Damien Elmes
7972708029 Remove rslib cargo config
Was added during initial Bazel experimentation back in 2020
2022-11-27 17:50:36 +10:00
Damien Elmes
5e0a761b87
Move away from Bazel (#2202)
(for upgrading users, please see the notes at the bottom)

Bazel brought a lot of nice things to the table, such as rebuilds based on
content changes instead of modification times, caching of build products,
detection of incorrect build rules via a sandbox, and so on. Rewriting the build
in Bazel was also an opportunity to improve on the Makefile-based build we had
prior, which was pretty poor: most dependencies were external or not pinned, and
the build graph was poorly defined and mostly serialized. It was not uncommon
for fresh checkouts to fail due to floating dependencies, or for things to break
when trying to switch to an older commit.

For day-to-day development, I think Bazel served us reasonably well - we could
generally switch between branches while being confident that builds would be
correct and reasonably fast, and not require full rebuilds (except on Windows,
where the lack of a sandbox and the TS rules would cause build breakages when TS
files were renamed/removed).

Bazel achieves that reliability by defining rules for each programming language
that define how source files should be turned into outputs. For the rules to
work with Bazel's sandboxing approach, they often have to reimplement or
partially bypass the standard tools that each programming language provides. The
Rust rules call Rust's compiler directly for example, instead of using Cargo,
and the Python rules extract each PyPi package into a separate folder that gets
added to sys.path.

These separate language rules allow proper declaration of inputs and outputs,
and offer some advantages such as caching of build products and fine-grained
dependency installation. But they also bring some downsides:

- The rules don't always support use-cases/platforms that the standard language
tools do, meaning they need to be patched to be used. I've had to contribute a
number of patches to the Rust, Python and JS rules to unblock various issues.
- The dependencies we use with each language sometimes make assumptions that do
not hold in Bazel, meaning they either need to be pinned or patched, or the
language rules need to be adjusted to accommodate them.

I was hopeful that after the initial setup work, things would be relatively
smooth-sailing. Unfortunately, that has not proved to be the case. Things
frequently broke when dependencies or the language rules were updated, and I
began to get frustrated at the amount of Anki development time I was instead
spending on build system upkeep. It's now about 2 years since switching to
Bazel, and I think it's time to cut losses, and switch to something else that's
a better fit.

The new build system is based on a small build tool called Ninja, and some
custom Rust code in build/. This means that to build Anki, Bazel is no longer
required, but Ninja and Rust need to be installed on your system. Python and
Node toolchains are automatically downloaded like in Bazel.

This new build system should result in faster builds in some cases:

- Because we're using cargo to build now, Rust builds are able to take advantage
of pipelining and incremental debug builds, which we didn't have with Bazel.
It's also easier to override the default linker on Linux/macOS, which can
further improve speeds.
- External Rust crates are now built with opt=1, which improves performance
of debug builds.
- Esbuild is now used to transpile TypeScript, instead of invoking the TypeScript
compiler. This results in faster builds, by deferring typechecking to test/check
time, and by allowing more work to happen in parallel.

As an example of the differences, when testing with the mold linker on Linux,
adding a new message to tags.proto (which triggers a recompile of the bulk of
the Rust and TypeScript code) results in a compile that goes from about 22s on
Bazel to about 7s in the new system. With the standard linker, it's about 9s.

Some other changes of note:

- Our Rust workspace now uses cargo-hakari to ensure all packages agree on
available features, preventing unnecessary rebuilds.
- pylib/anki is now a PEP420 implicit namespace, avoiding the need to merge
source files and generated files into a single folder for running. By telling
VSCode about the extra search path, code completion now works with generated
files without needing to symlink them into the source folder.
- qt/aqt can't use PEP420 as it's difficult to get rid of aqt/__init__.py.
Instead, the generated files are now placed in a separate _aqt package that's
added to the path.
- ts/lib is now exposed as @tslib, so the source code and generated code can be
provided under the same namespace without a merging step.
- MyPy and PyLint are now invoked once for the entire codebase.
- dprint will be used to format TypeScript/json files in the future instead of
the slower prettier (currently turned off to avoid causing conflicts). It can
automatically defer to prettier when formatting Svelte files.
- svelte-check is now used for typechecking our Svelte code, which revealed a
few typing issues that went undetected with the old system.
- The Jest unit tests now work on Windows as well.

If you're upgrading from Bazel, updated usage instructions are in docs/development.md and docs/build.md. A summary of the changes:

- please remove node_modules and .bazel
- install rustup (https://rustup.rs/)
- install rsync if not already installed  (on windows, use pacman - see docs/windows.md)
- install Ninja (unzip from https://github.com/ninja-build/ninja/releases/tag/v1.11.1 and
  place on your path, or from your distro/homebrew if it's 1.10+)
- update .vscode/settings.json from .vscode.dist
2022-11-27 15:24:20 +10:00
Stefan Kangas
5551a37f03
Fix typos (#2210) 2022-11-24 20:18:57 +10:00
Damien Elmes
ade2738458 Fix invalid utf8 not being detected
- Rusqlite was returning a different error
- The sort field may also contain invalid utf8
2022-11-22 13:27:20 +10:00
Damien Elmes
063623af3c Format .toml files with dprint 2022-11-09 20:03:49 +10:00
dobefore
0c9cecd7a3
Fix error while compiling rslib (#2187)
* protobuf generate error

pass --experimental_allow_proto3_optional to protoc
add missing dereive trait to struct Daylimit

* delete invalid derive trait Eq

* remove argument from protoc

--experimental_allow_proto3_optional
2022-11-09 12:36:23 +10:00
Damien Elmes
c9a9f38ea9 Remove untranslated 'see old deck options' notice
It was intended to be a temporary message, and it's been about 15 months.

https://forums.ankiweb.net/t/anki-2-1-55-beta-3/24295/42
2022-11-03 12:05:19 +10:00
Abdo
95d0c78b78
Fix issue when dragged deck is a prefix of target (#2149) 2022-10-29 09:42:34 +10:00
Abdo
abbfdbf420
Fix grandchild tag not being reparentable under the same root (#2148)
Introduced in #2146
2022-10-29 09:39:44 +10:00
Abdo
951c80a4e9
Fix some issues with tag reparenting (#2146)
* Fix reparented_name not correctly handling tags that are prefixes of the
new parent

To reproduce the issue:
1. Add two tags: `a` and `ab`.
2. From the browser's sidebar, drag & drop `a` into `ab`.

Result: panic

* Fix reparent_tags panicking if new parent is a child of source tag

This is the "foo, foo::bar" case that should be a no-op.

* Add more tests for tag reparenting
2022-10-28 21:42:10 +10:00
RumovZ
c521753057
Refactor error handling (#2136)
* Add crate snafu

* Replace all inline structs in AnkiError

* Derive Snafu on AnkiError

* Use snafu for card type errors

* Use snafu whatever error for InvalidInput

* Use snafu for NotFoundError and improve message

* Use snafu for FileIoError to attach context

Remove IoError.
Add some context-attaching helpers to replace code returning bare
io::Errors.

* Add more context-attaching io helpers

* Add message, context and backtrace to new snafus

* Utilize error context and backtrace on frontend

* Rename LocalizedError -> BackendError.
* Remove DocumentedError.
* Have all backend exceptions inherit BackendError.

* Rename localized(_description) -> message

* Remove accidentally committed experimental trait

* invalid_input_context -> ok_or_invalid

* ensure_valid_input! -> require!

* Always return `Err` from `invalid_input!`

Instead of a Result to unwrap, the macro accepts a source error now.

* new_tempfile_in_parent -> new_tempfile_in_parent_of

* ok_or_not_found -> or_not_found

* ok_or_invalid -> or_invalid

* Add crate convert_case

* Use unqualified lowercase type name

* Remove uses of snafu::ensure

* Allow public construction of InvalidInputErrors (dae)

Needed to port the AnkiDroid changes.

* Make into_protobuf() public (dae)

Also required for AnkiDroid. Not sure why it worked previously - possible
bug in older Rust version?
2022-10-21 18:02:12 +10:00
RumovZ
b8c294bf4d
Explicitly evaluate symlink on Windows (#2135) 2022-10-19 20:08:58 +10:00
Damien Elmes
fb9c934ef2 Use protoc from Bazel if missing from path
Closes #2134
2022-10-17 09:58:51 +10:00
Damien Elmes
cfb309e6b3 Update Rust deps 2022-09-24 13:22:46 +10:00
Damien Elmes
a39a3b4d34 Update to latest rules_rust and Rust 1.64 2022-09-24 11:12:58 +10:00
Damien Elmes
b97a8bfa26 Fix daily counts being included in apkg import
Fixes https://github.com/ankidroid/Anki-Android/issues/12477
2022-09-24 09:05:29 +10:00
Damien Elmes
09cb8b3cf6 Always scan for media changes
The check runs in the background, and the dentry cache and SQLite
page cache should make this more efficient after the first run.

Closes #1736
2022-09-20 16:13:10 +10:00
RumovZ
e7af0febb1
More template checks (#2032)
* Show warning if multiple type boxes are used

* Report templates referencing media in Media Check

* Apply suggestions from code review

* Fix media-check.ftl

* Only report media references with fields

Like `<img src={{Front}}>`.
Also report Anki sound tags and latex.

* Loop existing media regexes
2022-09-05 16:52:25 +10:00
RumovZ
e39fb74e82
Enable state-dependent custom scheduling data (#2049)
* Enable state-dependent custom scheduling data

* Next(Card)States -> SchedulingStates

The fact that `current` was included in `next` always bothered me,
and custom data is part of the card state, so that was a bit confusing
too.

* Store custom_data in SchedulingState

* Make custom_data optional when answering

Avoids having to send it 4 extra times to the frontend, and avoids the
legacy answerCard() API clobbering the stored data.

Co-authored-by: Damien Elmes <gpg@ankiweb.net>
2022-09-05 16:48:01 +10:00
Damien Elmes
0bcb3a3564 Add non-legacy backend interface for adding new decks 2022-09-04 14:12:29 +10:00
RumovZ
1f8189fe91
Some import/export features and fixes (#2038)
* Keep filtered decks when importing apkg

If all original decks exist and scheduling is included.

* Create missing decks from csv

* Export original decks if with_scheduling

* Also remap original deck ids on import

* Update imported filtered decks

* Fix meta column being mapped to tags

* Fix ids in csv deck and notetype columns

Note: This implies names which parse to an i64 will be seen as ids,
likely resulting in the intended deck/notetype not being found.

* Check for scheduling with revlog and deck configs

Might help with cases in which scheduling was included, but all cards
are new. In such a case, filtered deck should not be converted.

* Fix duplicate with same GUID being created

* Remove redundant `distinct`s from sql query

* Match notes by _either_ guid _or_ first field

* Refactor to emphasise GUID/first field distinction

* Export default deck and config if with scheduling

* Fix default deck being exported if it's a parent
2022-09-03 11:29:06 +10:00
RumovZ
31b7464c67
Add card meta for persisting custom scheduling state (#2040)
* Add card meta for persisting custom scheduling state

* Rename meta -> custom_data

* Enforce limits on size of custom data

Large values will slow down table scans of the cards table, and it's
easier to be strict now and possibly relax things in the future than
the opposite.

* Pack card states and customData into a single message

+ default customData to empty if it can't be parsed

Co-authored-by: Damien Elmes <gpg@ankiweb.net>
2022-09-02 11:22:49 +10:00
Matthias Metelka
d110c4916c
Introduce setting to collapse field by default (#1990)
* Introduce setting to collapse field by default

* Fix schema order

* Change wording from adjective to imperative

sounds a bit less clunky

* Update rslib/src/notetype/schema11.rs (dae)

* Keep settings in single column

* Add back Toggle Visual Editor string

* Add RichTextBadge component and show it conditionally

* Reverse input order depending on default setting

* Make PlainTextInput border-radius responsive to toggle states

* Prevent first Collapsible transition differently

* Focus inputs after Collapsible transition

The double tick calls are just a temporary solution until I find the exact moment an input is focusable again.

* Use requestAnimationFrame to await focusable state

Note: Svelte tick doesn't seem to work in this scenario.
2022-08-31 23:34:39 +10:00
RumovZ
79fbb6c8d8
Keep content of unmapped fields when importing (#2023)
* Keep content of unmapped fields when importing

* Test new behaviour

* Fix typo in `canonify_tags_without_resgistering`

* Log updated note instead of original one

* Revert merging imported tags

But keep old note tags if no new ones are provided.
2022-08-24 16:04:32 +10:00
Matthias Metelka
d1cbb86178
Default input setting in fields dialog (#1987)
* Introduce field setting to use plain text editor by default

* Remove leftover function from #1476

* Use boolean instead of string

* Simplify clear_other_field_duplicates

* Convert plain text key to camelCase

* Move HTML item below the existing checkbox, instead of to the right (dae)

Showing it on the right is more space efficient, but feels a bit
cluttered IMHO.
2022-08-18 12:30:18 +10:00
Damien Elmes
bd2f866c68 Fix {{CardFlags}} not working with flags 5-7
https://forums.ankiweb.net/t/please-activate-flags-5-7-on-the-cardflag/22143
2022-08-08 10:56:07 +10:00