Commit graph

387 commits

Author SHA1 Message Date
Jarrett Ye
055b6e30f8
update FSRS-rs to 0.5.0 & export benchmark API (#3056)
* update fsrs to 0.4.5

* update to fsrs 0.4.6

* add benchmark API

* update fsrs to 0.5.0

* cargo fmt

* ./ninja fix:minilints

* ./ninja format

* Add a brief comment about the new method (dae)
2024-03-08 12:37:06 +00:00
Abdo
9228c87b3a
Show preset and original deck in card info (#3055)
* Show preset and original deck in card info

* Make original_deck optional
2024-03-07 07:47:55 +00:00
Abdo
60f8399aed
Show total review count when optimizing FSRS parameters (#3027)
* Show total review count when optimizing FSRS parameters

* Do not expose items
2024-02-26 13:27:22 +07:00
Abdo
6843d65ed1
Check required review count for FSRS after filtering (#3019)
* Check for required review count for FSRS after filtering

* Remove unreachable check

* Update minimum review count in optimal retention calculation

* Fix review check in optimal retention routine too
2024-02-24 14:53:38 +07:00
Luc Mcgrady
8b18a08b3b
FSRS - Ignore revlogs before date while optimizing (#2922)
* Added: Date input button

* Added: ignoreDate to config

* Added: Backend

* Optimize function passes value

* Fix: Spelling

* Moved: filter logic from revlog_for_srs to update_memory_state

* fmt

* Copyright header

* ./check

* Fix: Test

* Renamed: Ignore_date -> Ignore_before_date

* Neaten parameters

* evaluate weights

* ./check

* Optimize all presets

* Added: Label localizations

* Removed globe label

* Added: Tooltip

* Changed error type

* fmt

* Moved filter to own function

* missing function call replacement

* Fix: Typo

* Apply suggestions from code review

Co-authored-by: Damien Elmes <dae@users.noreply.github.com>

* timestamp * 1000 -> timestamp_millis

* ignoreBefore -> ignore_before

* clarified ignore_before variables

* i64 -> TimestampMillis

* Un-traitified remove_revlogs_before

* Added: ms == 0 guard

* Added: Ignore_before affects scheduling

* Moved filter to fsrs_items_for_training

* removed filter from revlog_for_srs

* Tuple -> UpdateMemoryStateEntry

* Removed unused function

* Removed superfluous _ms from variables

* cid -> id

* Different ignore method

* Added: Unit test

* cid -> id

* Test: Exact ms edge case

* ./check

* Fix: re-learns could be before ignore date in cards without learning steps

* getignoreRevlogsBeforeMs -> getIgnoreRevlogsBeforeMs

* Removed pub(crate)

* Clarified unit test

* last_learn_entry -> first_of_last_learn_entries

* @user1823's method

* IOS fix

* ./check

* Fix: width defined twice
2024-02-22 11:01:10 +07:00
Abdo
4ef389b580
Keep previous FSRS parameters if they get worse when optimizing (#2996)
* Update to fsrs-rs 0.3.0

* Keep previous FSRS parameters if they get worse when optimizing
2024-02-11 16:26:04 +10:00
Abdo
80c14aa6e9
Maintain original IO cloze order in editing mode (#2987)
* Maintain original IO cloze order in editing mode

* Fix ordinal propery name
2024-02-07 13:42:47 +10:00
Abdo
eab5c02251
Add by creation date review sort order (#2957)
* Add by creation date review sort order

* Order by template after nid in ReverseAdded of filtered decks too
2024-01-21 20:29:19 +10:00
Damien Elmes
bf06020855
Use card.reps - 1 when calculating fuzz (#2933)
https://github.com/open-spaced-repetition/fsrs4anki-helper/issues/343#issuecomment-1879584562

https://forums.ankiweb.net/t/reschedule-is-inconsistent-with-normal-schedule-in-fuzz/39363
2024-01-09 12:26:46 +10:00
Damien Elmes
4678b0cc4a Use seconds instead of minutes for preview delay
Since this is not compatible with older clients, preview_delay has been
brought back so the configured value will still sync.
2023-12-21 11:02:29 +10:00
Damien Elmes
e778cba089 Allow user to configure hard/good buttons when rescheduling off
Closes #2858
2023-12-08 11:04:34 +10:00
Gustaf-C
63260631e4
Include elapsed_secs in learning card state (#2862)
* Include elapsed_time in learning card state

* Suggested updates, elapsed_time -> elapsed_secs

* Remove outdated comment
2023-12-06 16:40:22 +10:00
Damien Elmes
063b6f60fd Rework error dialog
- Hide traceback
- Include full add-on info in 'copy debug info' button, like about
screen
- Link to troubleshooting page
- Use non-modal pop-up in the common case, to avoid potential conflicts
with other modals.

Closes #2830
2023-11-29 10:25:32 +10:00
Damien Elmes
8b6abd3f8f Switch FSRS reschedule to a global option; don't persist
A global is easier to use in conjunction with the 'optimize all' action.
The value is no longer persisted, as doing so makes it too easy for users
to generate a lot of revlog entries when playing with different FSRS
weights/retention settings, such as in https://forums.ankiweb.net/t/possible-syncing-limitation-by-fsrs-manual-scheduling-data-accumulation/37610
2023-11-27 11:24:31 +10:00
Damien Elmes
452e012c71 Add option to calculate all weights at once 2023-11-27 11:24:31 +10:00
Mani
be1f889211
fixes: remove unfinished shapes, remove selectable and make shapes remain inside canvas (#2809)
* remove unfinished polygon and remove selectable for shapes in polygon mode

* make group and polygon position remain inside canvas area

* click through transparent area in grouped object

* add some shortcuts for basic usages

* tools button icon in center & switch mode border

* fix load svg image

* basic rtl support, panzoom have issues in rtl mode

* better zoom option both in ltr and rtl

* handle zoom event in mask editor

* add h button to handle toggle mask

* add more mime type

* use capital M (shift+m) for toggle mask

* allow io shortcuts in mask editor only

* make other shapes also remain in canvas bound area

* better zoom implementation, zoom from center
add zoom to resize event listener

* add a border to corner to handle blend of control

* add refresh button to go to  selection menu

* add tooltip to shortcuts and also add shortcut for other tools

* make opacity remain in same state when toggled on

* opacity for group/ungroup objects

* update shortcuts implementation
2023-11-24 14:06:40 +10:00
Damien Elmes
366f78715b Include next_day timestamp in revlog export 2023-11-23 14:46:48 +10:00
Damien Elmes
a9d73fc3be Add a method for exporting revlogs in binary 2023-11-22 11:57:40 +10:00
Abdo
390935d4ea
Persist FSRS weights search in preset (#2827) 2023-11-14 11:47:08 +10:00
RumovZ
39a60bc3a4
Allow applying limits of inactive parents (#2824)
* Allow applying limits of inactive parents

* Tweak label/help text (dae)
2023-11-13 14:30:19 +10:00
RumovZ
f200d6248e
Allow im-/exporting with or without deck configs (#2804)
* Allow im-/exporting with or without deck configs

Closes #2777.

* Enable webengine remote debugging in launch.json

* Reset deck limits and counts based on scheduling

Also:
- Fix `deck.common` not being reset.
- Apply all logic only depending on the source collection in the
gathering stage.
- Skip checking for scheduling and only act based on whether the call
wants scheduling. Preservation of filtered decks also depends on all
original decks being included.
- Fix check_ids() not covering revlog.

* Fix importing legacy filtered decks w/o scheduling

* Disable 'include deck options' by default, and fix tab order (dae)

* deck options > deck presets (dae)
2023-11-13 13:54:41 +10:00
Abdo
ae7b14bf40
Add auto-advance options to deck preset (#2765)
* Move stop-timer-on-answer strings to correct section

* Add auto-advance options to deck preset

* Implement answer actions

* Fix error when last card is answered before timeout

* Fix deserialization of answerAction

* Add answerAction to reserved key list

* Fix inverted boolean

* Add option to wait for audio to finish

* Add auto-advance toggle

* Add shortcut

* Disable auto-advance when main window state changes

* Start auto-advance timer after option is toggled

* Disable auto-advance when main window loses focus

* Use existing translations

* Add Answer Hard and Show Reminder
2023-11-13 10:41:51 +10:00
Abdo
6a2d1f94d4
Move anki.utils.html_to_text_line() to backend (#2816) 2023-11-09 09:57:23 +10:00
Damien Elmes
9268dce707 Expose fuzz delta for FSRS add-on 2023-11-06 12:27:53 +10:00
Gustaf-C
e071fb471b
Allow creation of empty filtered decks (#2788)
* Add new button to UI

* Add bool to allow creating empty filtered in back end

* Implement logic into front end for passing on bool

* Hide option on old decks

* Show option again if any settings are changed

* Revert "Show option again if any settings are changed"

This reverts commit 094acd9c65936823fa206594da5c1f3e4eb09248.

* Revert "Hide option on old decks"

This reverts commit d20a9a240b4fd85d080e8cc52d94318416ca753f.

* Update string

* Update ftl/core/decks.ftl

---------

Co-authored-by: Damien Elmes <dae@users.noreply.github.com>
2023-11-05 12:23:14 +10:00
Damien Elmes
633d246306 Don't lock collection while generating TTS 2023-10-26 11:45:17 +10:00
Abdo
14940a617b
Fix IO groups breaking upon editing (#2766)
* Fix IO groups breaking upon editing

* Emit change signal after group/ungroup
2023-10-23 09:43:31 +10:00
Damien Elmes
9bbc6c9405 Add image occlusion to stock notetypes 2023-10-22 11:00:39 +10:00
Aristotelis
c828a2eb6f
Add APIs for IO card rendering (#2739)
* Refactor: Add index to shapes package

* Add shape draw callback API to setupImageCloze

* Expose IO drawing API, switch away from image cloze naming

We currently use "image occlusion" in most places, but some references to "image cloze" still remain. For consistency's sake and to make it easier to quickly find IO-related code, this commit replaces all remaining references to "image cloze", only maintaining those required for backwards compatibility with existing note types.

* Add cloze ordinal to shapes

* Do not mutate original shapes during (de)normalization

Mutating shapes would be a recipe for trouble when combined with IO API use by external consumers.

(makeNormal(makeAbsolute(makeNormal())) is not idempotent,
and keeping track of the original state would introduce
additional complexity with no discernible performance benefit
or otherwise.)

* Tweak IO API, allowing modifications to ShapeProperties

* Tweak drawShape parameters

* Switch method order

For consistency with previous implementation

* Run Rust formatters

* Simplify position (de)normalization

---------

Co-authored-by: Glutanimate <glutanimate@users.noreply.github.com>
2023-10-20 09:36:46 +10:00
Abdo
bba67fdab4
Fix misleading warning when changing notetype from/to cloze (#2744) 2023-10-18 16:50:32 +10:00
Abdo
5cde4b6941
Remove v1/v2 support from the backend (#2727)
* Remove v1/v2 support from deck list

* Remove v1/v2 support from most routines and show error

* Remove scheduler_version from preferences

* Fix formatting

* Remove v1/v2 conditionals from Python code

* Fix legacy importer

* Remove legacy hooks

* Add missing scheduler checks

* Remove V2 logic from deck options screen

* Remove the review_did_undo hook

* Restore ability to open old options with shift (dae)
2023-10-14 10:50:59 +10:00
Damien Elmes
003cdfd2ec Use sm2 retention when deriving memory state
Closes #2702
2023-10-13 10:37:35 +10:00
Abdo
9e147c6335
Add text tool to image occlusion (#2705)
* Add text tool to IO

* Remove unnecessary parentheses

* Fix text objects always grouped

* Remove log

* Fix text objects hidden on back side

* Implement text scaling

* Add inverse text outline

* Warn about IO notes with only text objects

This will result in a different error message than the case where no
objects are added at all though, and the user can bypass the warning.
Maybe this is better to avoid discarding the user's work if they have
spent some time adding text.

* Add isValidType

* Use matches!

* Lock aspect ratio of text objects

* Reword misleading comment

The confusion probably comes from the Fabric docs, which apparently need updating: http://fabricjs.com/docs/fabric.Canvas.html#uniformScaling

* Do not count text objects when calculating current index

* Make text objects respond to size changes

* Fix uniform scaling not working when editing

* Use Arial font

* Escape colons and unify parsing

* Handle scale factor when restricting shape to view

* Use 'cloned'

* Add text background

* Tweak drawShape's params
2023-10-12 13:40:11 +10:00
Abdo
c052be9e25
Add a backend method to extract static media references (#2716)
* Add a backend method to extract static media references

* Extract into Notetype.gather_media_names()
2023-10-11 14:10:02 +10:00
RumovZ
23f29a6ecc
Invalid sorting (#2709)
* Rollback if toggling state fails

Previously, if the search triggered by a state toggle failed, the switch
and the model would move to the new state, while the table would remain
in the previous state.

* Fix reversed sort orders of FSRS columns

* Add sep. default sort orders for notes and cards

* Add test for consistent default sort orders

* Add launch config for debugging in VSC

* Extend launch config for macOS and Linux
2023-10-07 06:36:15 +00:00
Damien Elmes
9fd8a8bb40 Add stability graph 2023-10-01 15:44:33 +10:00
Damien Elmes
072cd37b42 Support rescheduling on weight/retention change 2023-10-01 15:20:58 +10:00
Damien Elmes
50c8a1ba9f Update FSRS
- up to 10x performance increase in optimal retention
- expose loss aversion
- use SpinBoxes
2023-09-30 16:10:22 +10:00
Damien Elmes
b8390d096e Shift weight calculation to backend so it can be run in parallel 2023-09-28 09:10:54 +10:00
Damien Elmes
1f55ad1d44
Expose the ability to train weights from items (#2687) 2023-09-28 08:28:24 +10:00
Abdo
ab7e64865e
Implement "stop timer on answer" as a preset option (#2686)
* Implement "stop timer on answer" as a preset option

* Hide timer setting on AnkiMobile (dae)
2023-09-27 16:10:14 +10:00
Damien Elmes
baae685dbb UI tweaks
https://forums.ankiweb.net/t/anki-23-10-beta-1/34912/19
2023-09-25 15:54:18 +10:00
Damien Elmes
e6aaeb85e9 Expose memory state computation to Python
Closes #2676
2023-09-25 11:05:47 +10:00
Damien Elmes
9cc4720efe Support fetching new cards by deck then random note
https://forums.ankiweb.net/t/feature-request-option-for-new-card-gather-order-that-prioritizes-subdecks-closer-to-top-but-gathers-cards-randomly-from-each-subdeck/23178
2023-09-24 11:54:10 +10:00
Damien Elmes
2126ff9a16 Gate graph display on fsrs status 2023-09-23 15:59:02 +10:00
Damien Elmes
03edb7bf9e Store desired retention in card data
If we want to be able to factor the desired retention into a sort based
on relative overdueness, having the values accessible on the card makes
things easier.
2023-09-23 15:42:42 +10:00
Damien Elmes
c78de23cf9 Convert FSRS to a global option
Allowing some decks to be FSRS and some SM-2 will lead to confusing
behavior when sorting on SM-2 or FSRS-specific fields, or when moving
cards between decks.
2023-09-23 14:41:55 +10:00
Abdo
f78c59176e
Add an option to stop the timer on answer (#2673)
* Add an option to stop the timer on answer

* Fix tab order
2023-09-23 14:01:03 +10:00
Abdo
c2b1ab5eb0
Skip template checks in Fields screen (#2670) 2023-09-20 16:09:54 +10:00
Damien Elmes
6074865763 Calculate parameters automatically
Logic derived from d8e2f6a0ff

Closes #2661
2023-09-18 16:43:36 +10:00
Damien Elmes
a7b4c90146 Use field tags instead of hard-coding occlusion fields
+ Don't protect the comments field

It's not required by our current code. We can remove the protection
from Header and Back Extra in the future too, once we no longer depend
on them.

Closes #2621
2023-09-18 10:10:11 +10:00
Damien Elmes
f0be697b55 Protect image occlusion fields and cloze field 2023-09-17 14:22:25 +10:00
Damien Elmes
1e37c806e5 Add support for tagging + protecting fields 2023-09-17 14:03:42 +10:00
Damien Elmes
59759b468f Start on a 'get params' button 2023-09-17 12:58:13 +10:00
Damien Elmes
812f5bc8be Bump version to 23.10
A stable release before October is unlikely at this point
2023-09-17 11:51:47 +10:00
Damien Elmes
0301ae1d8a fsrs_memory_state -> memory_state 2023-09-17 11:50:38 +10:00
Damien Elmes
5004cd332b
Integrate FSRS into Anki (#2654)
* Pack FSRS data into card.data

* Update FSRS card data when preset or weights change

+ Show FSRS stats in card stats

* Show a warning when there's a limited review history

* Add some translations; tweak UI

* Fix default requested retention

* Add browser columns, fix calculation of R

* Property searches

eg prop:d>0.1

* Integrate FSRS into reviewer

* Warn about long learning steps

* Hide minimum interval when FSRS is on

* Don't apply interval multiplier to FSRS intervals

* Expose memory state to Python

* Don't set memory state on new cards

* Port Jarret's new tests; add some helpers to make tests more compact

https://github.com/open-spaced-repetition/fsrs-rs/pull/64

* Fix learning cards not being given memory state

* Require update to v3 scheduler

* Don't exclude single learning step when calculating memory state

* Use relearning step when learning steps unavailable

* Update docstring

* fix single_card_revlog_to_items (#2656)

* not need check the review_kind for unique_dates

* add email address to CONTRIBUTORS

* fix last first learn & keep early review

* cargo fmt

* cargo clippy --fix

* Add Jarrett to about screen

* Fix fsrs_memory_state being initialized to default in get_card()

* Set initial memory state on graduate

* Update to latest FSRS

* Fix experiment.log being empty

* Fix broken colpkg imports

Introduced by "Update FSRS card data when preset or weights change"

* Update memory state during (re)learning; use FSRS for graduating intervals

* Reset memory state when cards are manually rescheduled as new

* Add difficulty graph; hide eases when FSRS enabled

* Add retrievability graph

* Derive memory_state from revlog when it's missing and shouldn't be

---------

Co-authored-by: Jarrett Ye <jarrett.ye@outlook.com>
2023-09-16 16:09:26 +10:00
Abdo
6f0bf58d49
Add a backend method to add notes in bulk (#2659)
* Add a backend method to add notes in bulk

* i -> idx

* Remove duplicate assignment

* Allow add_notes to work with multiple deck IDs

* Rename note_deck_id to requests
2023-09-16 13:51:32 +10:00
Damien Elmes
bfef908c6c
Refactor media sync handling (#2647)
* Refactor media sync handling

- The media USN is now returned in sync/meta, which avoids an extra
round-trip.
- Media syncing is now automatically started by the syncing code at
the end of a normal or full sync, which avoids it competing for bandwidth
and resources, and avoids duplicate invalid login messages when the auth
token is invalid.
- Added a new media_sync_progress() method to both check if media is
syncing, and get access to the latest progress.
- Updated the sync log screen to only show the latest line, like AnkiMobile.
- Show media sync errors in a pop-up, so they don't get missed. Use a non-modal
pop-up to avoid potential conflicts with other modals.

* Remove print statement
2023-09-10 13:22:20 +10:00
RumovZ
14de8451dc
Merging Notetypes on Import (#2612)
* Remember original id when importing notetype

* Reuse notetypes with matching original id

* Add field and template ids

* Enable merging imported notetypes

* Fix test

Note should be updated if the incoming note's notetype is
remapped to the existing note's notetype.
On the other hand, it should be skipped if its notetype id is mapped
to some new notetype.

* Change field and template ids to i32

* Add merge notetypes flag to proto message

* Add dialog for apkg import

* Move HelpModal into components

* Generalize import dialog

* Move SettingTitle into components

* Add help modal to ImportAnkiPackagePage

* Move SwitchRow into components

* Fix backend method import

* Make testable in browser

* Fix broken modal

* Wrap in container and fix margins

* Update commented Anki version of new proto fields

* Check ids when comparing notetype schemas

* Add tooltip for merging notetypes.

* Allow updating notes regardless of mtime

* Gitignore yarn-error.log

* Allow updating notetypes regardless of mtime

* Fix apkg help carousel

* Use i64s for template and field ids

* Add option to omit importing scheduling info

* Restore last settings in apkg import dialog

* Display error when getting metadata in webview

* Update manual links for apkg importing

* Apply suggestions from code review

Co-authored-by: Damien Elmes <dae@users.noreply.github.com>

* Omit schduling -> Import all cards as new cards

* Tweak importing-update-notes-help

* UpdateCondition → ImportAnkiPackageUpdateCondition

* Load keyboard.ftl

* Skip updating dupes in 'update alwyas' case

* Explain more when merging notetypes is required

* "omit scheduling" → "with scheduling"

* Skip updating notetype dupes if 'update always'

* Merge duplicated notetypes from previous imports

* Fix rebase aftermath

* Fix panic when merging

* Clarify 'update notetypes' help

* Mention 'merge notetypes' in the log

* Add a test which covers the previously panicking path

* Use nested ftl messages to ensure consistency

* Make order of merged fields deterministic

* Rewrite test to trigger panic

* Update version comment on new fields
2023-09-09 09:00:55 +10:00
Damien Elmes
ffd392de21
Change Anki's version scheme; bump to 23.09 (#2640)
* Accept iterables as inputs to backend methods

* Shift add-on check to backend; use new endpoint

The new endpoint will return info on a suitable branch if found,
instead of returning all branches. This simplifies the frontend code,
and means that you can now drop support for certain versions without
it also remotely disabling the add-on for people who are running one of
the excluded versions, like in

https://forums.ankiweb.net/t/prevent-add-ons-from-being-disabled-remote-stealthily-surreptitiously/33427

* Bump version to 23.09

This changes Anki's version numbering system to year.month.patch, as
previously mentioned on https://forums.ankiweb.net/t/use-a-different-versioning-system-semver-perhaps/20046/5

This is shaping up to be a big release, with the introduction of FSRS and
image occlusion, and it seems like a good time to be finally updating the
version scheme as well. AnkiWeb has been updated to understand the new
format, and add-on authors will now specify version compatibility using
the full version number, as can be seen here:

https://ankiweb.net/shared/info/3918629684

* Shift update check to backend, and tidy up update.py

* Use the shared client for sync connections too
2023-09-07 12:37:15 +10:00
Damien Elmes
6d34d19808 Drop legacy schema option 2023-09-06 15:49:14 +10:00
Damien Elmes
0c6e3eaa93
Integrate the FSRS optimizer (#2633)
* Support searching for deck configs by name

* Integrate FSRS optimizer into Anki

* Hack in a rough implementation of evaluate_weights()

* Interrupt calculation if user closes dialog

* Fix interrupted error check

* log_loss/rmse

* Update to latest fsrs commit; add progress info to weight evaluation

* Fix progress not appearing when pretrain takes a while

* Update to latest commit
2023-09-05 18:45:05 +10:00
Abdo
98715e593a
Improve presentation of importing results (#2568)
* Implement import log screen in Svelte

* Show filename in import log screen title

* Remove unused NoteRow property

* Show number of imported notes

* Use a single nid expression

* Use 'count' as variable name for consistency

* Import from @tslib/backend instead

* Fix summary_template typing

* Fix clippy warning

* Apply suggestions from code review

* Fix imports

* Contents -> Fields

* Increase max length of browser search bar

https://github.com/ankitects/anki/pull/2568/files#r1255227035

* Fix race condition in Bootstrap tooltip destruction

https://github.com/twbs/bootstrap/issues/37474

* summary_template -> summaryTemplate

* Make show link a button

* Run import ops on Svelte side

* Fix geometry not being restored in CSV Import page

* Make VirtualTable fill available height

* Keep CSV dialog modal

* Reword importing-existing-notes-skipped

* Avoid mentioning matching based on first field

* Change tick and cross icons

* List skipped notes last

* Pure CSS spinner

* Move set_wants_abort() call to relevant dialogs

* Show number of imported cards

* Remove bold from first sentence and indent summaries

* Update UI after import operations

* Add close button to import log page

Also make virtual table react to resize event.

* Fix typing

* Make CSV dialog non-modal again

Otherwise user can't interact with browser window.

* Update window modality after import

* Commit DB and update undo actions after import op

* Split frontend proto into separate file, so backend can ignore it

Currently the automatically-generated frontend RPC methods get placed in
'backend.js' with all the backend methods; we could optionally split them
into a separate 'frontend.js' file in the future.

* Migrate import_done from a bridgecmd to a HTTP request

* Update plural form of importing-notes-added

* Move import response handling to mediasrv

* Move task callback to script section

* Avoid unnecessary :global()

* .log cannot be missing if result exists

* Move import log search handling to mediasrv

* Type common params of ImportLogDialog

* Use else if

* Remove console.log()

* Add way to test apkg imports in new log screen

* Remove unused import

* Get actual card count for CSV imports

* Use import type

* Fix typing error

* Ignore import log when checking for changes in Python layer

* Apply suggestions from code review

* Remove imported card count for now

* Avoid non-null assertion in assignment

* Change showInBrowser to take an array of notes

* Use dataclasses for import log args

* Simplify ResultWithChanges in TS

* Only abort import when window is modal

* Fix ResultWithChanges typing

* Fix Rust warnings

* Only log one duplicate per incoming note

* Update wording about note updates

* Remove caveat about found_notes

* Reduce font size

* Remove redundant map

* Give credit to loading.io

* Remove unused line

---------

Co-authored-by: RumovZ <gp5glkw78@relay.firefox.com>
2023-08-02 20:29:44 +10:00
Damien Elmes
ffadbf577b deckconfig.proto -> deck_config.proto
Makes it consistent with our other proto files, and matches the service
name.
2023-07-03 13:44:54 +10:00
Damien Elmes
dc56a2ca7d Rework RenderCardOutput::question/answer
Instead of flattening the output (which was missing FrontSide), alter
the behaviour of render() instead. The non-partial output is now exposed
via Protobuf, so the non-Python clients can take advantage of it.
2023-06-27 00:37:41 +10:00
Damien Elmes
0173ebf384 Fix lack of progress/error when importing a .colpkg
We should be accessing the backend progress state, instead of the
collection's state.
2023-06-22 09:46:09 +10:00
Damien Elmes
b37063e20a More service generation refactoring
- Dropped the protobuf extensions in favor of explicitly listing out
methods in both services if we want to implement both, as it's clearer.
- Move Service/Method wrappers into a separate crate that the various
clients can import, to easily get at the list of backend services and
their correct indices and comments.
2023-06-22 09:46:09 +10:00
Damien Elmes
46722d792d Use a separate service definition for backend-only services
Realised this is clearer than tagging each method individually. The
enum has been retained for the case where we want to implement the backend
method separately from the collection one.
2023-06-19 22:06:50 +10:00
Damien Elmes
553303fc12
Refactor service generation (#2552)
* Automatically elide empty inputs and outputs to backend methods

* Refactor service generation

Despite the fact that the majority of our Protobuf service methods require
an open collection, they were not accessible with just a Collection
object. To access the methods (e.g. because we haven't gotten around to
exposing the correct API in Collection yet), you had to wrap the collection
in a Backend object, and pay a mutex-acquisition cost for each call, even
if you have exclusive access to the object.

This commit migrates the majority of service methods to the Collection, so
they can now be used directly, and improves the ergonomics a bit at the
same time.

The approach taken:

- The service generation now happens in rslib instead of anki_proto, which
avoids the need for trait constraints and associated types.
- Service methods are assumed to be collection-based by default. Instead of
implementing the service on Backend, we now implement it on Collection, which
means our methods no longer need to use self.with_col(...).
- We automatically generate methods in Backend which use self.with_col() to
delegate to the Collection method.
- For methods that are only appropriate for the backend, we add a flag in
the .proto file. The codegen uses this flag to write the method into a
BackendFooService instead of FooService, which the backend implements.
- The flag can also allows us to define separate implementations for collection
and backend, so we can e.g. skip the collection mutex in the i18n service
while also providing the service on a collection.
2023-06-19 15:33:40 +10:00
Damien Elmes
45f5709214
Migrate to protobuf-es (#2547)
* Fix .no-reduce-motion missing from graphs spinner, and not being honored

* Begin migration from protobuf.js -> protobuf-es

Motivation:

- Protobuf-es has a nicer API: messages are represented as classes, and
fields which should exist are not marked as nullable.
- As it uses modules, only the proto messages we actually use get included
in our bundle output. Protobuf.js put everything in a namespace, which
prevented tree-shaking, and made it awkward to access inner messages.
- ./run after touching a proto file drops from about 8s to 6s on my machine. The tradeoff
is slower decoding/encoding (#2043), but that was mainly a concern for the
graphs page, and was unblocked by
37151213cd

Approach/notes:

- We generate the new protobuf-es interface in addition to existing
protobuf.js interface, so we can migrate a module at a time, starting
with the graphs module.
- rslib:proto now generates RPC methods for TS in addition to the Python
interface. The input-arg-unrolling behaviour of the Python generation is
not required here, as we declare the input arg as a PlainMessage<T>, which
marks it as requiring all fields to be provided.
- i64 is represented as bigint in protobuf-es. We were using a patch to
protobuf.js to get it to output Javascript numbers instead of long.js
types, but now that our supported browser versions support bigint, it's
probably worth biting the bullet and migrating to bigint use. Our IDs
fit comfortably within MAX_SAFE_INTEGER, but that may not hold for future
fields we add.
- Oneofs are handled differently in protobuf-es, and are going to need
some refactoring.

Other notable changes:

- Added a --mkdir arg to our build runner, so we can create a dir easily
during the build on Windows.
- Simplified the preference handling code, by wrapping the preferences
in an outer store, instead of a separate store for each individual
preference. This means a change to one preference will trigger a redraw
of all components that depend on the preference store, but the redrawing
is cheap after moving the data processing to Rust, and it makes the code
easier to follow.
- Drop async(Reactive).ts in favour of more explicit handling with await
blocks/updating.
- Renamed add_inputs_to_group() -> add_dependency(), and fixed it not adding
dependencies to parent groups. Renamed add() -> add_action() for clarity.

* Remove a couple of unused proto imports

* Migrate card info

* Migrate congrats, image occlusion, and tag editor

+ Fix imports for multi-word proto files.

* Migrate change-notetype

* Migrate deck options

* Bump target to es2020; simplify ts lib list

Have used caniuse.com to confirm Chromium 77, iOS 14.5 and the Chrome
on Android support the full es2017-es2020 features.

* Migrate import-csv

* Migrate i18n and fix missing output types in .js

* Migrate custom scheduling, and remove protobuf.js

To mostly maintain our old API contract, we make use of protobuf-es's
ability to convert to JSON, which follows the same format as protobuf.js
did. It doesn't cover all case: users who were previously changing the
variant of a type will need to update their code, as assigning to a new
variant no longer automatically removes the old one, which will cause an
error when we try to convert back from JSON. But I suspect the large majority
of users are adjusting the current variant rather than creating a new one,
and this saves us having to write proxy wrappers, so it seems like a
reasonable compromise.

One other change I made at the same time was to rename value->kind for
the oneofs in our custom study protos, as 'value' was easily confused
with the 'case/value' output that protobuf-es has.

With protobuf.js codegen removed, touching a proto file and invoking
./run drops from about 8s to 6s.

This closes #2043.

* Allow tree-shaking on protobuf types

* Display backend error messages in our ts alert()

* Make sourcemap generation opt-in for ts-run

Considerably slows down build, and not used most of the time.
2023-06-14 22:47:37 +10:00
Damien Elmes
a83c4a7da7 Move generated protobuf into anki_proto
Due to the orphan rule, this meant removing our usages of impl ProtoStruct,
or converting them to a trait when they were used commonly.

rslib now directly references anki_proto and anki_i18n, instead of
'pub use'-ing them, and we can put the generated files back in OUT_DIR.
2023-06-12 15:47:51 +10:00
Damien Elmes
bac05039a7 Move protobuf generation into a separate crate; write .py interface in Rust
A couple of motivations for this:

- genbackend.py was somewhat messy, and difficult to change with the
lack of types. The mobile clients used it as a base for their generation,
so improving it will make life easier for them too, once they're ported.
- It will make it easier to write a .ts generator in the future
- We currently implement a bunch of helper methods on protobuf types
which don't allow us to compile the protobuf types until we compile
the Anki crate. If we change this in the future, we will be able to
do more of the compilation up-front.

We no longer need to record the services in the proto file, as we can
extract the service order from the compiled protos. Support for map types
has also been added.
2023-06-12 09:52:00 +10:00
Damien Elmes
686b596d08 AVTags -> AvTags
Avoids having to special-case string inflection in interface generation
2023-06-11 19:18:32 +10:00
Damien Elmes
f758b33346
Default to current deck in csv import if settings allow it (#2527)
* Default to current deck in csv import if settings allow it

Reuses defaults_for_adding(). In the future we might also want to update
the last deck/notetype on successful completion, if entries weren't
specified in the file.

https://forums.ankiweb.net/t/importing-new-notes-to-wrong-deck-in-anki-2-1-63/30598

* Address review feedback from Rumo
2023-05-31 13:47:12 +10:00
Damien Elmes
f6486da233
Various tweaks to I/O code (#2478)
* Allow user to select I/O notetype instead of enforcing a specific name

* Display a clearer error when I/O note is missing an image

Opening the card layout screen from "manage notetypes" was showing an
error about the Anki version being too old.

Replacement error is not currently translatable.

* Preserve existing notetype when adding I/O notetype

* Add a 'from clipboard' string

The intention is to use this in the future to allow an image occlusion
to be created from an image on the clipboard.

* Tweak I/O init

- Use union type instead of multiple nullable values
- Pass the notetype id in to initialization

* Fix image insertion in I/O note

- The regex expected double quotes, and we were using single ones
- Image tags don't need to be closed

* Use more consistent naming in image_occlusion.proto

* Tweaks to default I/O notetype

- Show the header on the front side as well (I presume this is what
users expect; if not am happy to revert)
- Don't show comments on card (again, I presume users expect to use
this field to add notes that aren't displayed during review, as they
can use back extra for that)

* Fix sticky footer missing background

Caused by earlier CSS refactoring
2023-04-19 15:30:18 +10:00
Damien Elmes
dd13e78eca
Add ability to restore a notetype to its original configuration (#2472)
* Store the original stock notetype kind in the notetype

Will allow us to provide a command to restore a notetype to its default
settings/templates.

* Add a new action to restore a notetype to its original state
2023-04-18 14:07:51 +10:00
Damien Elmes
d9624819e9 Add a fully-random review order
https://forums.ankiweb.net/t/bug-the-random-option-in-the-review-sort-order-setting-is-not-truly-random/29199
2023-04-11 16:16:45 +10:00
Mani
2bf134dc72
Feature image occlusion (#2367)
* add note types with occlusions and image fields

* generate image occlusion cloze div data
- generate div element with data-* atrributes for canvas shape generate for reviewer

* getting image data & deck id and adding notes
the implementation added into backend
- added service index in backend.proto for image occlusion request
- created image_occlusion.proto with required message and service
- implementation in backend for getting image and adding notes, also during editing return imagecloze note and update notes
- add notes to selected deck, if no notetype then add image occlusion notetypes
- reuse notetype from stock notetypes when not exist

* script for generating shapes using canvas api in reviewer
- the flash issues fixed by loading image and using image size to draw canvas, also when image get resized, calculate scale using natural width and canvas width to draw shape at right position
- limit size of canvas for safari

* init image occlusion page in ts and build page
with
- fabricjs for editing shapes
- panzoom for drag and zoom
- pickr for color picker
- build page using web.rs

* implement top toolbar for canvas shapes
- undo & redo tools
- zoom in, zoom out and zoom fit
- group & ungroup
- copy & paste
- set transparency of shapes
- align tools

* implement side toolbar for drawing shapes
add top toolbar and the side toolbar contains following tools
- cursor for selecting shapes
- zoom for drag and zoom shapes in mask editor
- rectangle for creating it
- ellipse for creating it
- polygon for creating it using points
- shape fill color
- question mask color (currently only single color can be added for all shapes)

* add maskeditor page for editing mask
- add side toolbar and sidebar include toptoolbar
- load maskeditor in two mode
     - for adding note using path to image
     - for editing note using note id

* implement note editor page for adding notes
- the note editor page have simple button (B/I/U) and option to toggle html view
- option to select deck for adding notes into that deck
- option to generate to hide all, guess one & hide one, guess one notes

* add image occlusion page
add side toolbar, top toolbar, mask editor and note editor
- option to switch between mask editor and note editor

* implement generates notes and save notes
implemention to show toast components for messages

* removed pickr & implemented color picker component
- remove pickr
- implemented using html5 canvas
- range input for changing color
- another range input for opacity changes
- hex and rgba value support

* rename methods name & rust unwrap safety
- change plural names to singular
- create respone message in proto and return response with imagecloze note or error if not found with note id
- remove image_occlusion from post handler list
- rename service name in mediasrv.py
- rename methods name for image occlusion in backend and image_occlusion
- update frontend also for update functions' names
- handle error in frontend mask-editor.ts, when error getting notes then toast message shown to frontend

* extract to function & add comments & remove global
- extract function in mask-editor.ts to reduce duplicate
- remove unused global from css
- add comments to store.ts explaining usage
- changes id to noteId in lib.ts
- add comments for limitSize, becuase of duplicate implementation

* remove image_occlusion notetype
- remove from stock notetype, stdmodels
- add implementation for notetype to image occlusion
- add i18n for errors

* update smooth scroll, always show cursor tools
- change questionmask to qmask
- make selectable for shape true in all tools to simplify edits and draw shapes
- update image occlusion in reviewer ts to load image properly

* add and get notetype else return errors

* fix: not showing occlusion

* Use a oneof for ImageClozeNoteResponse

Makes it clearer that only one of them can be returned

* Don't crash if image filename not provided

The second unwrap should be ok, as the input is utf8

* Refactor get_image_cloze_note

- fixes crash when note doesn't exist - Ok(None) case was not covered
- decouples business logic from native error->proto error conversion
- no need for original copy
- field[x] is more idiomatic than field.get(x).unwrap()
- don't need mutable access to fields

* Fix crash if image file unreadable

+ Use our read_file helper for better error context

* Add metadata() helper

* Fix crash if file metadata can't be read

* remove color picker, qmask and shape color
- remove strings from ftl
- remove color picker component
- remove from cloze generation
- remove icons for two buttons
- use constant color for shapes

* update color in reviewer and ftl strings

* fix shape position in canvas & add border to shape
- rename mask to inactive shape and active shape color
- border witdth and border color
- change decimal point deserializing string and toFixed(2)
- add thin border in mask editor, may be image background was transparent

* fix shape position in canvas after modified
- do not draw fixed ratio shapes by turn of uniformScaling
- fix rectangle width,height
- fix ellipse rx,ry,width,height
- fix polygon postion and points
- draw outside of canvas also

* fix border width and color in reviewer canvas
- rename variable

* refactor cloze div generate and remove angle

* fix origin when drawn outside of canvas from right

* fix shape at boundry & not include rx,ry rectangle
- move shapes at boundry when pointer is outside of canvas
- include rx, ry for ellipse only
- include points for polygon only

* fix lint errors & update image size in editor canvas based on height and width

* remove unsupported layerX & layerX for touchscreen
- fix shapes at edges

* implemented undo redo with canvas state

- implemented undo redo using fabric canvas events
- polygon is special case and implemented only added and modified event
- rectangle and ellipse have object:added, object:modified and object:removed case
- change id to undo and redo

* remove background image from canvas and used css to put image tag below canvas editor

- set image width and height after adding image

* fix for polygon points, add br in cloze strings, & toogle masks button

- fix shapes at edges
- toggle masks button to show/hide masks
- hide clozes string, it contains <br>
- set height for div container (used 'relative' in css)

* refactor top toolbar, add space and border radius
- rename cursor tools
- add left and right border

* fix undo after undo happen, use transparent color in draw mode
2023-03-29 12:33:19 +10:00
Kieran Black
fe591f6be7
fix stats calendar incorrect due to daylight savings time (#2456)
* fix stats calendar daylight saving time offset bug

Previously, when computing counts for the calendar in the stats menu, it was assumed that days had 86,400 seconds. However, this assumption does not hold true on the day when daylight savings occurs.

* add self to CONTRIBUTORS and about.py

* fix stats calendar anki day to calendar day mapping

Since Anki days don't necessarily roll over at midnight, mapping an Anki day into a calendar day needs to have a linear shift applied. By providing the frontend with access to the scheduler's rollover hour, we can account for this offset.
2023-03-28 15:35:06 +10:00
Abdo
946eb46813
Add option to exclude fields from search (#2394)
* Add option to exclude fields from unqualified searches

* Use temp tables instead

This is slightly faster according to my (very rough) tests.

* Make query a bit more readable

* exclude_from_search -> excludeFromSearch

* Remove superfluous notetypes table from query

* Rework to use field search logic

Thanks to Rumo for the suggestion: https://github.com/ankitects/anki/pull/2394#issuecomment-1446702402

* Exclude fields from field searches too

* Fix error on notetypes with no included fields

* Add back the exclude_fields function

This approach seems to perform better on average than the previously
benchmarked ones.

* Use pure-SQL approach to excluding fields

* Change single field search to use new approach

* Fix flawed any_excluded/sortf_excluded logic

* Support field exclusion in the nc operator

Also fix search text being wrapped in % in the any_excluded=true case.

* Support field exclusion in the re and w operators

* Label field exclusion as being slower

* Unqualified search should be wrapped in % in all cases

I was under the impression that it shouldn't be wrapped with the new
field exclusion logic.

* Remove unnecessary .collect()

* Refactor some complex return types into structs

* Do not exclude fields in field searches

* Add a test and docstring for CollectRanges

* Avoid destructuring in closures

* Remove the exclude_fields function

Minor wording tweaks by dae:
* num_fields -> total_fields_in_note
* fields -> field_ranges_to_search
* fields -> fields_to_search
* SingleField -> FieldQualified
* mid -> ntid
2023-03-20 07:46:03 +10:00
RumovZ
bd88c6d352
Ensure state mutator runs after card is rendered (#2421)
* Ensure state mutator runs after card is rendered

* Ensure ease buttons only show when states are ready

* Pass context into states mutator

* Revert queuing of state mutator hook

Now that context data is exposed users shouldn't rely on the question
having been rendered anymore.

* Use callbacks instead of signals and timeout

... to track whether the states mutator ran or failed.

* Make mutator async

* Remove State enum

* Reduce requests and compute seed on backend
2023-03-16 16:31:00 +10:00
RumovZ
c4d5eeb7a3
Revert bury restriction (#2432)
* Remove outdated comment.

* Revert removal of independent bury rules

* Revert 'hierarchical bury modes'

It's now again allowed to bury new, but not review cards e.g., but
siblings of previously gathered card queues will not be buried.

* Tweak docs (dae)

* Add missing Learn and PreviewRepeat queues
2023-03-11 17:49:18 +10:00
RumovZ
bb297b95bc
Global new ignore review limit (#2417)
* Add CardAdder test helper

* Add option to have new cards ignore the review limit

Also entails a lot of refactoring because the old code was deeply
coupled to the previous behaviour.

* Add global option to ignore review limit

* Refactor decrementation

* Unify testing
2023-03-06 19:06:12 +10:00
RumovZ
85aebae573
Add option to tag notes with missing media (#2379)
* Keep track of notes with missing media files

* Add option to tag notes with missing media

* Update ftl/core/media-check.ftl (dae)
2023-02-20 18:48:09 +10:00
RumovZ
cdfb84f19a
Implement TTS using windows crate (#2371)
* Implement TTS using windows crate

* Use API calls instead of SSML

* Properly stop player in case of TTS error

* Add context to WindowsErrors

* Validate available voices

* Remove TTS text from synthesize error

* Limit maximum buffer size

* Make validation optional and list it in tts filter

* We no longer need the winrt module (dae)

* Use a separate request object so the meaning of the bool is clear (dae)

* Slightly shorten runtime error message (dae)

The default message appears to clip slightly.

* Alternate buffer implementation (dae)

* Use array instead of vec

* Drop the max buffer size to 128k (dae)
2023-02-17 12:26:07 +10:00
RumovZ
5a53da23ca
Deck scoped dupe check (#2372)
* Support limiting dupe check to deck

* Expose deck limiting dupe check on frontend

* Make CSV dupe options configurable with headers

* Rename duplicate file headers

* Change dupe check limit to enum
2023-02-16 17:53:36 +10:00
Damien Elmes
f616bea580 Allow the network timeout to be customized
https://forums.ankiweb.net/t/local-sync-server-collection-exceeds-size-limit/27183/7
2023-02-08 14:33:02 +10:00
Damien Elmes
567ba06b5c Show custom data in stats screen
https://forums.ankiweb.net/t/feature-request-display-custom-data-in-card-info/27187
2023-02-07 12:27:43 +10:00
RumovZ
c824dd0b90
Disable burying of previously gathered cards (#2361)
* Enforce hierarchical bury modes

Interday learning burying is only allowed if review burying is enabled
and review burying is only allowed if new burying is enabled.
Closes #2352.

* Switch front end to new bury modes

* Wording tweaks (dae)

* Hide interday option if using v2 scheduler (dae)
2023-02-06 12:02:27 +10:00
Kaben Nanlohy
77bba533ea
Allow burying cards in browser (#2351)
* Allow burying cards in browser

This code is based on existing "toggle suspend" command in browser.

- Adds "toggle bury" command to browser cards menu.
- Adds "browsing-toggle-bury" to core translation. Only english-language.
- Adds "buried" coloring to rows for buried cards in browser table.

Not yet done:

- Keyboard shortcut for "toggle bury" action.
- Non-english translations.

* Add contributor as requested in CONTRIBUTORS.

* Fix formatting in browser_table.rs.

* Add keyboard shortcut to "toggle bury" command.

This adds keyboard shortcut "ctrl-shift-j" to "toggle bury" command in
browser cards menu.

* Simplify logic for color of buried-card rows.
2023-01-30 19:21:06 +10:00
Damien Elmes
19bbcb4cc0 Use backend for extracting cloze text to type
Closes #2311
2023-01-18 23:05:28 +10:00
Damien Elmes
cf45cbf429
Rework syncing code, and replace local sync server (#2329)
This PR replaces the existing Python-driven sync server with a new one in Rust.
The new server supports both collection and media syncing, and is compatible
with both the new protocol mentioned below, and older clients. A setting has
been added to the preferences screen to point Anki to a local server, and a
similar setting is likely to come to AnkiMobile soon.

Documentation is available here: <https://docs.ankiweb.net/sync-server.html>

In addition to the new server and refactoring, this PR also makes changes to the
sync protocol. The existing sync protocol places payloads and metadata inside a
multipart POST body, which causes a few headaches:

- Legacy clients build the request in a non-deterministic order, meaning the
entire request needs to be scanned to extract the metadata.
- Reqwest's multipart API directly writes the multipart body, without exposing
the resulting stream to us, making it harder to track the progress of the
transfer. We've been relying on a patched version of reqwest for timeouts,
which is a pain to keep up to date.

To address these issues, the metadata is now sent in a HTTP header, with the
data payload sent directly in the body. Instead of the slower gzip, we now
use zstd. The old timeout handling code has been replaced with a new implementation
that wraps the request and response body streams to track progress, allowing us
to drop the git dependencies for reqwest, hyper-timeout and tokio-io-timeout.

The main other change to the protocol is that one-way syncs no longer need to
downgrade the collection to schema 11 prior to sending.
2023-01-18 12:43:46 +10:00
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
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
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
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
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