From 185e9acd22fa22295402a170eb87ca69480dee40 Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Sat, 10 Jul 2021 21:58:34 +1000 Subject: [PATCH] split out remaining tags, stats, media and rendering --- defs.bzl | 2 +- proto/anki/backend.proto | 265 ----------------------------- proto/anki/card_rendering.proto | 119 +++++++++++++ proto/anki/media.proto | 32 ++++ proto/anki/stats.proto | 64 +++++++ proto/anki/tags.proto | 60 +++++++ protobuf.bzl => proto/protobuf.bzl | 0 pylib/anki/BUILD.bazel | 17 +- pylib/anki/__init__.py | 22 +-- pylib/anki/_backend/genbackend.py | 12 +- pylib/anki/card_rendering_pb2.pyi | 1 + pylib/anki/collection.py | 14 +- pylib/anki/latex.py | 7 +- pylib/anki/media.py | 5 +- pylib/anki/media_pb2.pyi | 1 + pylib/anki/stats_pb2.pyi | 1 + pylib/anki/tags.py | 4 +- pylib/anki/tags_pb2.pyi | 1 + pylib/anki/template.py | 13 +- pylib/tools/protoc_wrapper.py | 5 +- rslib/src/backend_proto.rs | 4 + ts/graphs/AddedGraph.svelte | 6 +- ts/graphs/ButtonsGraph.svelte | 4 +- ts/graphs/CalendarGraph.svelte | 6 +- ts/graphs/CardCounts.svelte | 6 +- ts/graphs/EaseGraph.svelte | 6 +- ts/graphs/FutureDue.svelte | 6 +- ts/graphs/HourGraph.svelte | 4 +- ts/graphs/IntervalsGraph.svelte | 6 +- ts/graphs/ReviewsGraph.svelte | 4 +- ts/graphs/TodayStats.svelte | 4 +- ts/graphs/WithGraphData.svelte | 20 +-- ts/graphs/added.ts | 4 +- ts/graphs/buttons.ts | 10 +- ts/graphs/calendar.ts | 10 +- ts/graphs/card-counts.ts | 4 +- ts/graphs/ease.ts | 4 +- ts/graphs/future-due.ts | 4 +- ts/graphs/graph-helpers.ts | 4 +- ts/graphs/hours.ts | 10 +- ts/graphs/intervals.ts | 4 +- ts/graphs/reviews.ts | 8 +- ts/graphs/today.ts | 8 +- ts/lib/proto.ts | 4 +- 44 files changed, 413 insertions(+), 382 deletions(-) create mode 100644 proto/anki/card_rendering.proto create mode 100644 proto/anki/media.proto create mode 100644 proto/anki/stats.proto create mode 100644 proto/anki/tags.proto rename protobuf.bzl => proto/protobuf.bzl (100%) create mode 120000 pylib/anki/card_rendering_pb2.pyi create mode 120000 pylib/anki/media_pb2.pyi create mode 120000 pylib/anki/stats_pb2.pyi create mode 120000 pylib/anki/tags_pb2.pyi diff --git a/defs.bzl b/defs.bzl index eef38cd66..bda94d69e 100644 --- a/defs.bzl +++ b/defs.bzl @@ -3,7 +3,7 @@ load("@bazel_skylib//lib:versions.bzl", "versions") load("@rules_rust//rust:repositories.bzl", "rust_repositories") load("@anki//cargo:crates.bzl", "raze_fetch_remote_crates") load(":python.bzl", "setup_local_python") -load(":protobuf.bzl", "setup_protobuf_binary") +load("//proto:protobuf.bzl", "setup_protobuf_binary") load("//proto:format.bzl", "setup_clang_format") load("@build_bazel_rules_nodejs//:index.bzl", "node_repositories", "yarn_install") load("@io_bazel_rules_sass//:defs.bzl", "sass_repositories") diff --git a/proto/anki/backend.proto b/proto/anki/backend.proto index 7bcd88c6d..8a3f465e7 100644 --- a/proto/anki/backend.proto +++ b/proto/anki/backend.proto @@ -5,15 +5,6 @@ syntax = "proto3"; package anki.backend; -import "anki/generic.proto"; -import "anki/cards.proto"; -import "anki/collection.proto"; -import "anki/notes.proto"; -import "anki/notetypes.proto"; - -// Backend methods -/////////////////////////////////////////////////////////// - /// while the protobuf descriptors expose the order services are defined in, /// that information is not available in prost, so we define an enum to make /// sure all clients agree on the service index @@ -35,54 +26,6 @@ enum ServiceIndex { SERVICE_INDEX_CARDS = 14; } -service CardRenderingService { - rpc ExtractAVTags(ExtractAVTagsRequest) returns (ExtractAVTagsResponse); - rpc ExtractLatex(ExtractLatexRequest) returns (ExtractLatexResponse); - rpc GetEmptyCards(generic.Empty) returns (EmptyCardsReport); - rpc RenderExistingCard(RenderExistingCardRequest) - returns (RenderCardResponse); - rpc RenderUncommittedCard(RenderUncommittedCardRequest) - returns (RenderCardResponse); - rpc RenderUncommittedCardLegacy(RenderUncommittedCardLegacyRequest) - returns (RenderCardResponse); - rpc StripAVTags(generic.String) returns (generic.String); - rpc RenderMarkdown(RenderMarkdownRequest) returns (generic.String); -} - -service TagsService { - rpc ClearUnusedTags(generic.Empty) returns (collection.OpChangesWithCount); - rpc AllTags(generic.Empty) returns (generic.StringList); - rpc RemoveTags(generic.String) returns (collection.OpChangesWithCount); - rpc SetTagCollapsed(SetTagCollapsedRequest) returns (collection.OpChanges); - rpc TagTree(generic.Empty) returns (TagTreeNode); - rpc ReparentTags(ReparentTagsRequest) returns (collection.OpChangesWithCount); - rpc RenameTags(RenameTagsRequest) returns (collection.OpChangesWithCount); - rpc AddNoteTags(NoteIdsAndTagsRequest) - returns (collection.OpChangesWithCount); - rpc RemoveNoteTags(NoteIdsAndTagsRequest) - returns (collection.OpChangesWithCount); - rpc FindAndReplaceTag(FindAndReplaceTagRequest) - returns (collection.OpChangesWithCount); -} - -service StatsService { - rpc CardStats(cards.CardId) returns (generic.String); - rpc Graphs(GraphsRequest) returns (GraphsResponse); - rpc GetGraphPreferences(generic.Empty) returns (GraphPreferences); - rpc SetGraphPreferences(GraphPreferences) returns (generic.Empty); -} - -service MediaService { - rpc CheckMedia(generic.Empty) returns (CheckMediaResponse); - rpc TrashMediaFiles(TrashMediaFilesRequest) returns (generic.Empty); - rpc AddMediaFile(AddMediaFileRequest) returns (generic.String); - rpc EmptyTrash(generic.Empty) returns (generic.Empty); - rpc RestoreTrash(generic.Empty) returns (generic.Empty); -} - -// Backend -/////////////////////////////////////////////////////////// - message BackendInit { repeated string preferred_langs = 1; string locale_folder_path = 2; @@ -94,9 +37,6 @@ message I18nBackendInit { string locale_folder_path = 5; } -// Errors -/////////////////////////////////////////////////////////// - message BackendError { enum Kind { INVALID_INPUT = 0; @@ -121,208 +61,3 @@ message BackendError { // the error subtype Kind kind = 2; } - -// Messages -/////////////////////////////////////////////////////////// - -message RenderExistingCardRequest { - int64 card_id = 1; - bool browser = 2; -} - -message RenderUncommittedCardRequest { - notes.Note note = 1; - uint32 card_ord = 2; - notetypes.Notetype.Template template = 3; - bool fill_empty = 4; -} - -message RenderUncommittedCardLegacyRequest { - notes.Note note = 1; - uint32 card_ord = 2; - bytes template = 3; - bool fill_empty = 4; -} - -message RenderCardResponse { - repeated RenderedTemplateNode question_nodes = 1; - repeated RenderedTemplateNode answer_nodes = 2; - string css = 3; - bool latex_svg = 4; -} - -message RenderedTemplateNode { - oneof value { - string text = 1; - RenderedTemplateReplacement replacement = 2; - } -} - -message RenderedTemplateReplacement { - string field_name = 1; - string current_text = 2; - repeated string filters = 3; -} - -message ExtractAVTagsRequest { - string text = 1; - bool question_side = 2; -} - -message ExtractAVTagsResponse { - string text = 1; - repeated AVTag av_tags = 2; -} - -message AVTag { - oneof value { - string sound_or_video = 1; - TTSTag tts = 2; - } -} - -message TTSTag { - string field_text = 1; - string lang = 2; - repeated string voices = 3; - float speed = 4; - repeated string other_args = 5; -} - -message ExtractLatexRequest { - string text = 1; - bool svg = 2; - bool expand_clozes = 3; -} - -message ExtractLatexResponse { - string text = 1; - repeated ExtractedLatex latex = 2; -} - -message ExtractedLatex { - string filename = 1; - string latex_body = 2; -} - -message AddMediaFileRequest { - string desired_name = 1; - bytes data = 2; -} - -message CheckMediaResponse { - repeated string unused = 1; - repeated string missing = 2; - string report = 3; - bool have_trash = 4; -} - -message TrashMediaFilesRequest { - repeated string fnames = 1; -} - -message CongratsLearnMessageRequest { - float next_due = 1; - uint32 remaining = 2; -} - -message SetTagCollapsedRequest { - string name = 1; - bool collapsed = 2; -} - -message GetChangedTagsResponse { - repeated string tags = 1; -} - -message TagTreeNode { - string name = 1; - repeated TagTreeNode children = 2; - uint32 level = 3; - bool collapsed = 4; -} - -message ReparentTagsRequest { - repeated string tags = 1; - string new_parent = 2; -} - -message RenameTagsRequest { - string current_prefix = 1; - string new_prefix = 2; -} - -message EmptyCardsReport { - message NoteWithEmptyCards { - int64 note_id = 1; - repeated int64 card_ids = 2; - bool will_delete_note = 3; - } - string report = 1; - repeated NoteWithEmptyCards notes = 2; -} - -message NoteIdsAndTagsRequest { - repeated int64 note_ids = 1; - string tags = 2; -} - -message FindAndReplaceTagRequest { - repeated int64 note_ids = 1; - string search = 2; - string replacement = 3; - bool regex = 4; - bool match_case = 5; -} - -message GraphsRequest { - string search = 1; - uint32 days = 2; -} - -message GraphsResponse { - repeated cards.Card cards = 1; - repeated RevlogEntry revlog = 2; - uint32 days_elapsed = 3; - // Based on rollover hour - uint32 next_day_at_secs = 4; - uint32 scheduler_version = 5; - /// Seconds to add to UTC timestamps to get local time. - int32 local_offset_secs = 7; -} - -message GraphPreferences { - enum Weekday { - SUNDAY = 0; - MONDAY = 1; - FRIDAY = 5; - SATURDAY = 6; - } - Weekday calendar_first_day_of_week = 1; - bool card_counts_separate_inactive = 2; - bool browser_links_supported = 3; - bool future_due_show_backlog = 4; -} - -message RevlogEntry { - enum ReviewKind { - LEARNING = 0; - REVIEW = 1; - RELEARNING = 2; - EARLY_REVIEW = 3; - MANUAL = 4; - } - int64 id = 1; - int64 cid = 2; - int32 usn = 3; - uint32 button_chosen = 4; - int32 interval = 5; - int32 last_interval = 6; - uint32 ease_factor = 7; - uint32 taken_millis = 8; - ReviewKind review_kind = 9; -} -message RenderMarkdownRequest { - string markdown = 1; - bool sanitize = 2; -} diff --git a/proto/anki/card_rendering.proto b/proto/anki/card_rendering.proto new file mode 100644 index 000000000..589293086 --- /dev/null +++ b/proto/anki/card_rendering.proto @@ -0,0 +1,119 @@ +// Copyright: Ankitects Pty Ltd and contributors +// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html + +syntax = "proto3"; + +package anki.card_rendering; + +import "anki/generic.proto"; +import "anki/notes.proto"; +import "anki/notetypes.proto"; + +service CardRenderingService { + rpc ExtractAVTags(ExtractAVTagsRequest) returns (ExtractAVTagsResponse); + rpc ExtractLatex(ExtractLatexRequest) returns (ExtractLatexResponse); + rpc GetEmptyCards(generic.Empty) returns (EmptyCardsReport); + rpc RenderExistingCard(RenderExistingCardRequest) + returns (RenderCardResponse); + rpc RenderUncommittedCard(RenderUncommittedCardRequest) + returns (RenderCardResponse); + rpc RenderUncommittedCardLegacy(RenderUncommittedCardLegacyRequest) + returns (RenderCardResponse); + rpc StripAVTags(generic.String) returns (generic.String); + rpc RenderMarkdown(RenderMarkdownRequest) returns (generic.String); +} + +message ExtractAVTagsRequest { + string text = 1; + bool question_side = 2; +} + +message ExtractAVTagsResponse { + string text = 1; + repeated AVTag av_tags = 2; +} + +message AVTag { + oneof value { + string sound_or_video = 1; + TTSTag tts = 2; + } +} + +message TTSTag { + string field_text = 1; + string lang = 2; + repeated string voices = 3; + float speed = 4; + repeated string other_args = 5; +} + +message ExtractLatexRequest { + string text = 1; + bool svg = 2; + bool expand_clozes = 3; +} + +message ExtractLatexResponse { + string text = 1; + repeated ExtractedLatex latex = 2; +} + +message ExtractedLatex { + string filename = 1; + string latex_body = 2; +} + +message EmptyCardsReport { + message NoteWithEmptyCards { + int64 note_id = 1; + repeated int64 card_ids = 2; + bool will_delete_note = 3; + } + string report = 1; + repeated NoteWithEmptyCards notes = 2; +} + +message RenderExistingCardRequest { + int64 card_id = 1; + bool browser = 2; +} + +message RenderUncommittedCardRequest { + notes.Note note = 1; + uint32 card_ord = 2; + notetypes.Notetype.Template template = 3; + bool fill_empty = 4; +} + +message RenderUncommittedCardLegacyRequest { + notes.Note note = 1; + uint32 card_ord = 2; + bytes template = 3; + bool fill_empty = 4; +} + +message RenderCardResponse { + repeated RenderedTemplateNode question_nodes = 1; + repeated RenderedTemplateNode answer_nodes = 2; + string css = 3; + bool latex_svg = 4; +} + +message RenderedTemplateNode { + oneof value { + string text = 1; + RenderedTemplateReplacement replacement = 2; + } +} + +message RenderedTemplateReplacement { + string field_name = 1; + string current_text = 2; + repeated string filters = 3; +} + +message RenderMarkdownRequest { + string markdown = 1; + bool sanitize = 2; +} diff --git a/proto/anki/media.proto b/proto/anki/media.proto new file mode 100644 index 000000000..f506615b8 --- /dev/null +++ b/proto/anki/media.proto @@ -0,0 +1,32 @@ +// Copyright: Ankitects Pty Ltd and contributors +// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html + +syntax = "proto3"; + +package anki.media; + +import "anki/generic.proto"; + +service MediaService { + rpc CheckMedia(generic.Empty) returns (CheckMediaResponse); + rpc TrashMediaFiles(TrashMediaFilesRequest) returns (generic.Empty); + rpc AddMediaFile(AddMediaFileRequest) returns (generic.String); + rpc EmptyTrash(generic.Empty) returns (generic.Empty); + rpc RestoreTrash(generic.Empty) returns (generic.Empty); +} + +message CheckMediaResponse { + repeated string unused = 1; + repeated string missing = 2; + string report = 3; + bool have_trash = 4; +} + +message TrashMediaFilesRequest { + repeated string fnames = 1; +} + +message AddMediaFileRequest { + string desired_name = 1; + bytes data = 2; +} diff --git a/proto/anki/stats.proto b/proto/anki/stats.proto new file mode 100644 index 000000000..21f69170e --- /dev/null +++ b/proto/anki/stats.proto @@ -0,0 +1,64 @@ +// Copyright: Ankitects Pty Ltd and contributors +// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html + +syntax = "proto3"; + +package anki.stats; + +import "anki/generic.proto"; +import "anki/cards.proto"; + +service StatsService { + rpc CardStats(cards.CardId) returns (generic.String); + rpc Graphs(GraphsRequest) returns (GraphsResponse); + rpc GetGraphPreferences(generic.Empty) returns (GraphPreferences); + rpc SetGraphPreferences(GraphPreferences) returns (generic.Empty); +} + +message GraphsRequest { + string search = 1; + uint32 days = 2; +} + +message GraphsResponse { + repeated cards.Card cards = 1; + repeated RevlogEntry revlog = 2; + uint32 days_elapsed = 3; + // Based on rollover hour + uint32 next_day_at_secs = 4; + uint32 scheduler_version = 5; + /// Seconds to add to UTC timestamps to get local time. + int32 local_offset_secs = 7; +} + +message GraphPreferences { + enum Weekday { + SUNDAY = 0; + MONDAY = 1; + FRIDAY = 5; + SATURDAY = 6; + } + Weekday calendar_first_day_of_week = 1; + bool card_counts_separate_inactive = 2; + bool browser_links_supported = 3; + bool future_due_show_backlog = 4; +} + +message RevlogEntry { + enum ReviewKind { + LEARNING = 0; + REVIEW = 1; + RELEARNING = 2; + EARLY_REVIEW = 3; + MANUAL = 4; + } + int64 id = 1; + int64 cid = 2; + int32 usn = 3; + uint32 button_chosen = 4; + int32 interval = 5; + int32 last_interval = 6; + uint32 ease_factor = 7; + uint32 taken_millis = 8; + ReviewKind review_kind = 9; +} diff --git a/proto/anki/tags.proto b/proto/anki/tags.proto new file mode 100644 index 000000000..a1597f7d6 --- /dev/null +++ b/proto/anki/tags.proto @@ -0,0 +1,60 @@ +// Copyright: Ankitects Pty Ltd and contributors +// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html + +syntax = "proto3"; + +package anki.tags; + +import "anki/generic.proto"; +import "anki/collection.proto"; + +service TagsService { + rpc ClearUnusedTags(generic.Empty) returns (collection.OpChangesWithCount); + rpc AllTags(generic.Empty) returns (generic.StringList); + rpc RemoveTags(generic.String) returns (collection.OpChangesWithCount); + rpc SetTagCollapsed(SetTagCollapsedRequest) returns (collection.OpChanges); + rpc TagTree(generic.Empty) returns (TagTreeNode); + rpc ReparentTags(ReparentTagsRequest) returns (collection.OpChangesWithCount); + rpc RenameTags(RenameTagsRequest) returns (collection.OpChangesWithCount); + rpc AddNoteTags(NoteIdsAndTagsRequest) + returns (collection.OpChangesWithCount); + rpc RemoveNoteTags(NoteIdsAndTagsRequest) + returns (collection.OpChangesWithCount); + rpc FindAndReplaceTag(FindAndReplaceTagRequest) + returns (collection.OpChangesWithCount); +} + +message SetTagCollapsedRequest { + string name = 1; + bool collapsed = 2; +} + +message TagTreeNode { + string name = 1; + repeated TagTreeNode children = 2; + uint32 level = 3; + bool collapsed = 4; +} + +message ReparentTagsRequest { + repeated string tags = 1; + string new_parent = 2; +} + +message RenameTagsRequest { + string current_prefix = 1; + string new_prefix = 2; +} + +message NoteIdsAndTagsRequest { + repeated int64 note_ids = 1; + string tags = 2; +} + +message FindAndReplaceTagRequest { + repeated int64 note_ids = 1; + string search = 2; + string replacement = 3; + bool regex = 4; + bool match_case = 5; +} diff --git a/protobuf.bzl b/proto/protobuf.bzl similarity index 100% rename from protobuf.bzl rename to proto/protobuf.bzl diff --git a/pylib/anki/BUILD.bazel b/pylib/anki/BUILD.bazel index f586402b5..ac9c29e89 100644 --- a/pylib/anki/BUILD.bazel +++ b/pylib/anki/BUILD.bazel @@ -32,7 +32,7 @@ py_library( "py.typed", ":buildinfo", ":hooks_gen", - ":proto", + ":proto_py", "//pylib/anki/_backend", ], imports = [ @@ -110,26 +110,17 @@ filegroup( load("//pylib:protobuf.bzl", "py_proto") py_proto( - name = "proto_files", + name = "proto_py", srcs = ["//proto"], visibility = [ "//visibility:public", ], ) -filegroup( - name = "proto", - srcs = [ - # "__init__.py", - ":proto_files", - ], - visibility = ["//pylib:__subpackages__"], -) - # only used for genbackend.py py_library( name = "proto_lib", - srcs = [":proto"], + srcs = [":proto_py", "__init__.py"], imports = [".."], - visibility = ["//pylib:__subpackages__"], + visibility = ["//visibility:public"], ) diff --git a/pylib/anki/__init__.py b/pylib/anki/__init__.py index d958c513c..e44d9d175 100644 --- a/pylib/anki/__init__.py +++ b/pylib/anki/__init__.py @@ -1,18 +1,20 @@ # Copyright: Ankitects Pty Ltd and contributors # License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html +import os import sys -from anki.buildinfo import version -from anki.collection import Collection +if not os.getenv("PROTOS_ONLY"): + from anki.buildinfo import version + from anki.collection import Collection -if sys.version_info[0] < 3 or sys.version_info[1] < 7: - raise Exception("Anki requires Python 3.7+") + if sys.version_info[0] < 3 or sys.version_info[1] < 7: + raise Exception("Anki requires Python 3.7+") -# ensure unicode filenames are supported -try: - "テスト".encode(sys.getfilesystemencoding()) -except UnicodeEncodeError as exc: - raise Exception("Anki requires a UTF-8 locale.") from exc + # ensure unicode filenames are supported + try: + "テスト".encode(sys.getfilesystemencoding()) + except UnicodeEncodeError as exc: + raise Exception("Anki requires a UTF-8 locale.") from exc -__all__ = ["Collection"] + __all__ = ["Collection"] diff --git a/pylib/anki/_backend/genbackend.py b/pylib/anki/_backend/genbackend.py index ce8310676..174a40f10 100755 --- a/pylib/anki/_backend/genbackend.py +++ b/pylib/anki/_backend/genbackend.py @@ -8,6 +8,8 @@ import sys import google.protobuf.descriptor +os.environ["PROTOS_ONLY"] = "1" + import anki.backend_pb2 import anki.i18n_pb2 import anki.cards_pb2 @@ -20,6 +22,10 @@ import anki.scheduler_pb2 import anki.sync_pb2 import anki.configs_pb2 import anki.search_pb2 +import anki.stats_pb2 +import anki.card_rendering_pb2 +import anki.tags_pb2 +import anki.media_pb2 import stringcase @@ -187,12 +193,16 @@ service_modules = dict( SYNC=anki.sync_pb2, CONFIGS=anki.configs_pb2, SEARCH=anki.search_pb2, + STATS=anki.stats_pb2, + CARD_RENDERING=anki.card_rendering_pb2, + TAGS=anki.tags_pb2, + MEDIA=anki.media_pb2, ) for service in anki.backend_pb2.ServiceIndex.DESCRIPTOR.values: # SERVICE_INDEX_TEST -> _TESTSERVICE base = service.name.replace("SERVICE_INDEX_", "") - service_pkg = service_modules.get(base) or anki.backend_pb2 + service_pkg = service_modules.get(base) service_var = "_" + base.replace("_", "") + "SERVICE" service_obj = getattr(service_pkg, service_var) service_index = service.number diff --git a/pylib/anki/card_rendering_pb2.pyi b/pylib/anki/card_rendering_pb2.pyi new file mode 120000 index 000000000..02d63405a --- /dev/null +++ b/pylib/anki/card_rendering_pb2.pyi @@ -0,0 +1 @@ +../../bazel-bin/pylib/anki/card_rendering_pb2.pyi \ No newline at end of file diff --git a/pylib/anki/collection.py b/pylib/anki/collection.py index e30d95362..bdcddf30f 100644 --- a/pylib/anki/collection.py +++ b/pylib/anki/collection.py @@ -7,15 +7,21 @@ from __future__ import annotations from typing import Any, Generator, List, Literal, Optional, Sequence, Tuple, Union, cast -import anki.backend_pb2 as _pb -from anki import collection_pb2, configs_pb2, generic_pb2, search_pb2 +from anki import ( + card_rendering_pb2, + collection_pb2, + configs_pb2, + generic_pb2, + search_pb2, + stats_pb2, +) from anki._legacy import DeprecatedNamesMixin, deprecated # protobuf we publicly export - listed first to avoid circular imports SearchNode = search_pb2.SearchNode Progress = collection_pb2.Progress -EmptyCardsReport = _pb.EmptyCardsReport -GraphPreferences = _pb.GraphPreferences +EmptyCardsReport = card_rendering_pb2.EmptyCardsReport +GraphPreferences = stats_pb2.GraphPreferences Preferences = configs_pb2.Preferences UndoStatus = collection_pb2.UndoStatus OpChanges = collection_pb2.OpChanges diff --git a/pylib/anki/latex.py b/pylib/anki/latex.py index b3f19385f..e1e31f228 100644 --- a/pylib/anki/latex.py +++ b/pylib/anki/latex.py @@ -10,8 +10,7 @@ from dataclasses import dataclass from typing import Any, List, Optional, Tuple import anki -import anki.backend_pb2 as _pb -from anki import hooks +from anki import card_rendering_pb2, hooks from anki.models import NotetypeDict from anki.template import TemplateRenderContext, TemplateRenderOutput from anki.utils import call, isMac, namedtmp, tmpdir @@ -45,7 +44,9 @@ class ExtractedLatexOutput: latex: List[ExtractedLatex] @staticmethod - def from_proto(proto: _pb.ExtractLatexResponse) -> ExtractedLatexOutput: + def from_proto( + proto: card_rendering_pb2.ExtractLatexResponse, + ) -> ExtractedLatexOutput: return ExtractedLatexOutput( html=proto.text, latex=[ diff --git a/pylib/anki/media.py b/pylib/anki/media.py index f452134e7..df9097a59 100644 --- a/pylib/anki/media.py +++ b/pylib/anki/media.py @@ -10,8 +10,7 @@ import sys import time from typing import Any, Callable, List, Optional, Tuple -import anki -import anki.backend_pb2 as _pb +from anki import media_pb2 from anki._legacy import deprecated from anki.consts import * from anki.latex import render_latex, render_latex_returning_errors @@ -27,7 +26,7 @@ def media_paths_from_col_path(col_path: str) -> Tuple[str, str]: return (media_folder, media_db) -CheckMediaResponse = _pb.CheckMediaResponse +CheckMediaResponse = media_pb2.CheckMediaResponse # fixme: look into whether we can drop chdir() below diff --git a/pylib/anki/media_pb2.pyi b/pylib/anki/media_pb2.pyi new file mode 120000 index 000000000..f86cbf1aa --- /dev/null +++ b/pylib/anki/media_pb2.pyi @@ -0,0 +1 @@ +../../bazel-bin/pylib/anki/media_pb2.pyi \ No newline at end of file diff --git a/pylib/anki/stats_pb2.pyi b/pylib/anki/stats_pb2.pyi new file mode 120000 index 000000000..b18a9af51 --- /dev/null +++ b/pylib/anki/stats_pb2.pyi @@ -0,0 +1 @@ +../../bazel-bin/pylib/anki/stats_pb2.pyi \ No newline at end of file diff --git a/pylib/anki/tags.py b/pylib/anki/tags.py index 7f3382fbd..757d102b9 100644 --- a/pylib/anki/tags.py +++ b/pylib/anki/tags.py @@ -16,15 +16,15 @@ import re from typing import Collection, List, Match, Optional, Sequence import anki # pylint: disable=unused-import -import anki.backend_pb2 as _pb import anki.collection +from anki import tags_pb2 from anki.collection import OpChanges, OpChangesWithCount from anki.decks import DeckId from anki.notes import NoteId from anki.utils import ids2str # public exports -TagTreeNode = _pb.TagTreeNode +TagTreeNode = tags_pb2.TagTreeNode MARKED_TAG = "marked" diff --git a/pylib/anki/tags_pb2.pyi b/pylib/anki/tags_pb2.pyi new file mode 120000 index 000000000..c9ec6d18f --- /dev/null +++ b/pylib/anki/tags_pb2.pyi @@ -0,0 +1 @@ +../../bazel-bin/pylib/anki/tags_pb2.pyi \ No newline at end of file diff --git a/pylib/anki/template.py b/pylib/anki/template.py index 588212665..ab4a57a4b 100644 --- a/pylib/anki/template.py +++ b/pylib/anki/template.py @@ -32,8 +32,7 @@ from dataclasses import dataclass from typing import Any, Dict, List, Optional, Sequence, Tuple, Union import anki -import anki.backend_pb2 as _pb -from anki import hooks +from anki import card_rendering_pb2, hooks from anki.cards import Card from anki.decks import DeckManager from anki.errors import TemplateError @@ -65,7 +64,9 @@ class PartiallyRenderedCard: latex_svg: bool @classmethod - def from_proto(cls, out: _pb.RenderCardResponse) -> PartiallyRenderedCard: + def from_proto( + cls, out: card_rendering_pb2.RenderCardResponse + ) -> PartiallyRenderedCard: qnodes = cls.nodes_from_proto(out.question_nodes) anodes = cls.nodes_from_proto(out.answer_nodes) @@ -73,7 +74,7 @@ class PartiallyRenderedCard: @staticmethod def nodes_from_proto( - nodes: Sequence[_pb.RenderedTemplateNode], + nodes: Sequence[card_rendering_pb2.RenderedTemplateNode], ) -> TemplateReplacementList: results: TemplateReplacementList = [] for node in nodes: @@ -90,7 +91,7 @@ class PartiallyRenderedCard: return results -def av_tag_to_native(tag: _pb.AVTag) -> AVTag: +def av_tag_to_native(tag: card_rendering_pb2.AVTag) -> AVTag: val = tag.WhichOneof("value") if val == "sound_or_video": return SoundOrVideoTag(filename=tag.sound_or_video) @@ -104,7 +105,7 @@ def av_tag_to_native(tag: _pb.AVTag) -> AVTag: ) -def av_tags_to_native(tags: Sequence[_pb.AVTag]) -> List[AVTag]: +def av_tags_to_native(tags: Sequence[card_rendering_pb2.AVTag]) -> List[AVTag]: return list(map(av_tag_to_native, tags)) diff --git a/pylib/tools/protoc_wrapper.py b/pylib/tools/protoc_wrapper.py index 14165c514..f98967aa1 100644 --- a/pylib/tools/protoc_wrapper.py +++ b/pylib/tools/protoc_wrapper.py @@ -12,7 +12,10 @@ import sys (protoc, mypy_protobuf, outdir, *protos) = sys.argv[1:] -prefix = "proto/" +if protos[0].startswith("external"): + prefix = "external/anki/proto/" +else: + prefix = "proto/" # invoke protoc subprocess.run( diff --git a/rslib/src/backend_proto.rs b/rslib/src/backend_proto.rs index 9b169547a..0925b97aa 100644 --- a/rslib/src/backend_proto.rs +++ b/rslib/src/backend_proto.rs @@ -14,6 +14,7 @@ macro_rules! protobuf { } protobuf!(backend); +protobuf!(card_rendering); protobuf!(cards); protobuf!(collection); protobuf!(configs); @@ -21,8 +22,11 @@ protobuf!(deckconfig); protobuf!(decks); protobuf!(generic); protobuf!(i18n); +protobuf!(media); protobuf!(notes); protobuf!(notetypes); protobuf!(scheduler); protobuf!(search); +protobuf!(stats); protobuf!(sync); +protobuf!(tags); diff --git a/ts/graphs/AddedGraph.svelte b/ts/graphs/AddedGraph.svelte index ec66af7b9..c3f56c64f 100644 --- a/ts/graphs/AddedGraph.svelte +++ b/ts/graphs/AddedGraph.svelte @@ -3,7 +3,7 @@ Copyright: Ankitects Pty Ltd and contributors License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html -->