Merge pull request #1286 from ankitects/proto
Split backend.proto into multiple files
This commit is contained in:
commit
0b9fbd9050
@ -1,5 +1,5 @@
|
||||
workspace(
|
||||
name = "net_ankiweb_anki",
|
||||
name = "ankidesktop",
|
||||
managed_directories = {"@npm": [
|
||||
"ts/node_modules",
|
||||
]},
|
||||
|
14
defs.bzl
14
defs.bzl
@ -1,10 +1,10 @@
|
||||
load("@bazel_skylib//:workspace.bzl", "bazel_skylib_workspace")
|
||||
load("@bazel_skylib//lib:versions.bzl", "versions")
|
||||
load("@rules_rust//rust:repositories.bzl", "rust_repositories")
|
||||
load("@net_ankiweb_anki//cargo:crates.bzl", "raze_fetch_remote_crates")
|
||||
load("@ankidesktop//cargo:crates.bzl", "raze_fetch_remote_crates")
|
||||
load(":python.bzl", "setup_local_python")
|
||||
load(":protobuf.bzl", "setup_protobuf_binary")
|
||||
load("//rslib:clang_format.bzl", "setup_clang_format")
|
||||
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")
|
||||
load("@com_github_ali5h_rules_pip//:defs.bzl", "pip_import")
|
||||
@ -35,7 +35,7 @@ def setup_deps():
|
||||
|
||||
pip_import(
|
||||
name = "py_deps",
|
||||
requirements = "@net_ankiweb_anki//pip:requirements.txt",
|
||||
requirements = "@ankidesktop//pip:requirements.txt",
|
||||
python_runtime = "@python//:python",
|
||||
)
|
||||
|
||||
@ -44,12 +44,12 @@ def setup_deps():
|
||||
python_runtime = "@python//:python",
|
||||
)
|
||||
|
||||
node_repositories(package_json = ["@net_ankiweb_anki//ts:package.json"])
|
||||
node_repositories(package_json = ["@ankidesktop//ts:package.json"])
|
||||
|
||||
yarn_install(
|
||||
name = "npm",
|
||||
package_json = "@net_ankiweb_anki//ts:package.json",
|
||||
yarn_lock = "@net_ankiweb_anki//ts:yarn.lock",
|
||||
package_json = "@ankidesktop//ts:package.json",
|
||||
yarn_lock = "@ankidesktop//ts:yarn.lock",
|
||||
)
|
||||
|
||||
sass_repositories()
|
||||
|
@ -74,14 +74,14 @@ index eff3d9df2..fb2e9f7fe 100644
|
||||
python_runtime = "@python//:python",
|
||||
)
|
||||
|
||||
- node_repositories(package_json = ["@net_ankiweb_anki//ts:package.json"])
|
||||
- node_repositories(package_json = ["@ankidesktop//ts:package.json"])
|
||||
+ native.local_repository(
|
||||
+ name = "local_node",
|
||||
+ path = "local_node",
|
||||
+ )
|
||||
+
|
||||
+ node_repositories(
|
||||
+ package_json = ["@net_ankiweb_anki//ts:package.json"],
|
||||
+ package_json = ["@ankidesktop//ts:package.json"],
|
||||
+ vendored_node = "@local_node//:node",
|
||||
+ )
|
||||
|
||||
|
0
proto/.top_level
Normal file
0
proto/.top_level
Normal file
32
proto/BUILD.bazel
Normal file
32
proto/BUILD.bazel
Normal file
@ -0,0 +1,32 @@
|
||||
# Copyright: Ankitects Pty Ltd and contributors
|
||||
# License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||
|
||||
load("@rules_proto//proto:defs.bzl", "proto_library")
|
||||
load("//proto:clang_format.bzl", "proto_format")
|
||||
|
||||
proto_format(
|
||||
name = "format",
|
||||
srcs = glob(["**/*.proto"]),
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
proto_library(
|
||||
name = "backend_proto_lib",
|
||||
srcs = glob(["**/*.proto"]),
|
||||
# "" removes the "proto/" prefix
|
||||
strip_import_prefix = "",
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "proto",
|
||||
srcs = glob(["**/*.proto"]),
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
exports_files([
|
||||
# for external workspace use
|
||||
"format.py",
|
||||
# an empty file we use to get the root proto/ path in the Rust build
|
||||
".top_level",
|
||||
])
|
63
proto/anki/backend.proto
Normal file
63
proto/anki/backend.proto
Normal file
@ -0,0 +1,63 @@
|
||||
// Copyright: Ankitects Pty Ltd and contributors
|
||||
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
package anki.backend;
|
||||
|
||||
/// 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
|
||||
enum ServiceIndex {
|
||||
SERVICE_INDEX_SCHEDULER = 0;
|
||||
SERVICE_INDEX_DECKS = 1;
|
||||
SERVICE_INDEX_NOTES = 2;
|
||||
SERVICE_INDEX_SYNC = 3;
|
||||
SERVICE_INDEX_NOTETYPES = 4;
|
||||
SERVICE_INDEX_CONFIG = 5;
|
||||
SERVICE_INDEX_CARD_RENDERING = 6;
|
||||
SERVICE_INDEX_DECK_CONFIG = 7;
|
||||
SERVICE_INDEX_TAGS = 8;
|
||||
SERVICE_INDEX_SEARCH = 9;
|
||||
SERVICE_INDEX_STATS = 10;
|
||||
SERVICE_INDEX_MEDIA = 11;
|
||||
SERVICE_INDEX_I18N = 12;
|
||||
SERVICE_INDEX_COLLECTION = 13;
|
||||
SERVICE_INDEX_CARDS = 14;
|
||||
}
|
||||
|
||||
message BackendInit {
|
||||
repeated string preferred_langs = 1;
|
||||
string locale_folder_path = 2;
|
||||
bool server = 3;
|
||||
}
|
||||
|
||||
message I18nBackendInit {
|
||||
repeated string preferred_langs = 4;
|
||||
string locale_folder_path = 5;
|
||||
}
|
||||
|
||||
message BackendError {
|
||||
enum Kind {
|
||||
INVALID_INPUT = 0;
|
||||
UNDO_EMPTY = 1;
|
||||
INTERRUPTED = 2;
|
||||
TEMPLATE_PARSE = 3;
|
||||
IO_ERROR = 4;
|
||||
DB_ERROR = 5;
|
||||
NETWORK_ERROR = 6;
|
||||
SYNC_AUTH_ERROR = 7;
|
||||
SYNC_OTHER_ERROR = 8;
|
||||
JSON_ERROR = 9;
|
||||
PROTO_ERROR = 10;
|
||||
NOT_FOUND_ERROR = 11;
|
||||
EXISTS = 12;
|
||||
FILTERED_DECK_ERROR = 13;
|
||||
SEARCH_ERROR = 14;
|
||||
}
|
||||
|
||||
// localized error description suitable for displaying to the user
|
||||
string localized = 1;
|
||||
// the error subtype
|
||||
Kind kind = 2;
|
||||
}
|
119
proto/anki/card_rendering.proto
Normal file
119
proto/anki/card_rendering.proto
Normal file
@ -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;
|
||||
}
|
64
proto/anki/cards.proto
Normal file
64
proto/anki/cards.proto
Normal file
@ -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.cards;
|
||||
|
||||
import "anki/generic.proto";
|
||||
import "anki/collection.proto";
|
||||
|
||||
service CardsService {
|
||||
rpc GetCard(CardId) returns (Card);
|
||||
rpc UpdateCard(UpdateCardRequest) returns (collection.OpChanges);
|
||||
rpc RemoveCards(RemoveCardsRequest) returns (generic.Empty);
|
||||
rpc SetDeck(SetDeckRequest) returns (collection.OpChangesWithCount);
|
||||
rpc SetFlag(SetFlagRequest) returns (collection.OpChangesWithCount);
|
||||
}
|
||||
message CardId {
|
||||
int64 cid = 1;
|
||||
}
|
||||
|
||||
message CardIds {
|
||||
repeated int64 cids = 1;
|
||||
}
|
||||
|
||||
message Card {
|
||||
int64 id = 1;
|
||||
int64 note_id = 2;
|
||||
int64 deck_id = 3;
|
||||
uint32 template_idx = 4;
|
||||
int64 mtime_secs = 5;
|
||||
sint32 usn = 6;
|
||||
uint32 ctype = 7;
|
||||
sint32 queue = 8;
|
||||
sint32 due = 9;
|
||||
uint32 interval = 10;
|
||||
uint32 ease_factor = 11;
|
||||
uint32 reps = 12;
|
||||
uint32 lapses = 13;
|
||||
uint32 remaining_steps = 14;
|
||||
sint32 original_due = 15;
|
||||
int64 original_deck_id = 16;
|
||||
uint32 flags = 17;
|
||||
string data = 18;
|
||||
}
|
||||
|
||||
message UpdateCardRequest {
|
||||
Card card = 1;
|
||||
bool skip_undo_entry = 2;
|
||||
}
|
||||
|
||||
message RemoveCardsRequest {
|
||||
repeated int64 card_ids = 1;
|
||||
}
|
||||
|
||||
message SetDeckRequest {
|
||||
repeated int64 card_ids = 1;
|
||||
int64 deck_id = 2;
|
||||
}
|
||||
|
||||
message SetFlagRequest {
|
||||
repeated int64 card_ids = 1;
|
||||
uint32 flag = 2;
|
||||
}
|
111
proto/anki/collection.proto
Normal file
111
proto/anki/collection.proto
Normal file
@ -0,0 +1,111 @@
|
||||
// Copyright: Ankitects Pty Ltd and contributors
|
||||
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
package anki.collection;
|
||||
|
||||
import "anki/generic.proto";
|
||||
|
||||
service CollectionService {
|
||||
rpc OpenCollection(OpenCollectionRequest) returns (generic.Empty);
|
||||
rpc CloseCollection(CloseCollectionRequest) returns (generic.Empty);
|
||||
rpc CheckDatabase(generic.Empty) returns (CheckDatabaseResponse);
|
||||
rpc GetUndoStatus(generic.Empty) returns (UndoStatus);
|
||||
rpc Undo(generic.Empty) returns (OpChangesAfterUndo);
|
||||
rpc Redo(generic.Empty) returns (OpChangesAfterUndo);
|
||||
rpc AddCustomUndoEntry(generic.String) returns (generic.UInt32);
|
||||
rpc MergeUndoEntries(generic.UInt32) returns (OpChanges);
|
||||
rpc LatestProgress(generic.Empty) returns (Progress);
|
||||
rpc SetWantsAbort(generic.Empty) returns (generic.Empty);
|
||||
}
|
||||
|
||||
message OpenCollectionRequest {
|
||||
string collection_path = 1;
|
||||
string media_folder_path = 2;
|
||||
string media_db_path = 3;
|
||||
string log_path = 4;
|
||||
}
|
||||
|
||||
message CloseCollectionRequest {
|
||||
bool downgrade_to_schema11 = 1;
|
||||
}
|
||||
|
||||
message CheckDatabaseResponse {
|
||||
repeated string problems = 1;
|
||||
}
|
||||
|
||||
message OpChanges {
|
||||
bool card = 1;
|
||||
bool note = 2;
|
||||
bool deck = 3;
|
||||
bool tag = 4;
|
||||
bool notetype = 5;
|
||||
bool config = 6;
|
||||
bool deck_config = 11;
|
||||
bool mtime = 12;
|
||||
|
||||
bool browser_table = 7;
|
||||
bool browser_sidebar = 8;
|
||||
// editor and displayed card in review screen
|
||||
bool note_text = 9;
|
||||
// whether to call .reset() and getCard()
|
||||
bool study_queues = 10;
|
||||
}
|
||||
|
||||
message OpChangesWithCount {
|
||||
uint32 count = 1;
|
||||
OpChanges changes = 2;
|
||||
}
|
||||
|
||||
message OpChangesWithId {
|
||||
int64 id = 1;
|
||||
OpChanges changes = 2;
|
||||
}
|
||||
|
||||
message UndoStatus {
|
||||
string undo = 1;
|
||||
string redo = 2;
|
||||
uint32 last_step = 3;
|
||||
}
|
||||
|
||||
message OpChangesAfterUndo {
|
||||
OpChanges changes = 1;
|
||||
string operation = 2;
|
||||
int64 reverted_to_timestamp = 3;
|
||||
UndoStatus new_status = 4;
|
||||
uint32 counter = 5;
|
||||
}
|
||||
|
||||
message Progress {
|
||||
message MediaSync {
|
||||
string checked = 1;
|
||||
string added = 2;
|
||||
string removed = 3;
|
||||
}
|
||||
|
||||
message FullSync {
|
||||
uint32 transferred = 1;
|
||||
uint32 total = 2;
|
||||
}
|
||||
|
||||
message NormalSync {
|
||||
string stage = 1;
|
||||
string added = 2;
|
||||
string removed = 3;
|
||||
}
|
||||
|
||||
message DatabaseCheck {
|
||||
string stage = 1;
|
||||
uint32 stage_total = 2;
|
||||
uint32 stage_current = 3;
|
||||
}
|
||||
oneof value {
|
||||
generic.Empty none = 1;
|
||||
MediaSync media_sync = 2;
|
||||
string media_check = 3;
|
||||
FullSync full_sync = 4;
|
||||
NormalSync normal_sync = 5;
|
||||
DatabaseCheck database_check = 6;
|
||||
}
|
||||
}
|
118
proto/anki/config.proto
Normal file
118
proto/anki/config.proto
Normal file
@ -0,0 +1,118 @@
|
||||
// Copyright: Ankitects Pty Ltd and contributors
|
||||
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
package anki.config;
|
||||
|
||||
import "anki/generic.proto";
|
||||
import "anki/collection.proto";
|
||||
|
||||
service ConfigService {
|
||||
rpc GetConfigJson(generic.String) returns (generic.Json);
|
||||
rpc SetConfigJson(SetConfigJsonRequest) returns (collection.OpChanges);
|
||||
rpc SetConfigJsonNoUndo(SetConfigJsonRequest) returns (generic.Empty);
|
||||
rpc RemoveConfig(generic.String) returns (collection.OpChanges);
|
||||
rpc GetAllConfig(generic.Empty) returns (generic.Json);
|
||||
rpc GetConfigBool(GetConfigBoolRequest) returns (generic.Bool);
|
||||
rpc SetConfigBool(SetConfigBoolRequest) returns (collection.OpChanges);
|
||||
rpc GetConfigString(GetConfigStringRequest) returns (generic.String);
|
||||
rpc SetConfigString(SetConfigStringRequest) returns (collection.OpChanges);
|
||||
rpc GetPreferences(generic.Empty) returns (Preferences);
|
||||
rpc SetPreferences(Preferences) returns (collection.OpChanges);
|
||||
}
|
||||
|
||||
message ConfigKey {
|
||||
enum Bool {
|
||||
BROWSER_TABLE_SHOW_NOTES_MODE = 0;
|
||||
PREVIEW_BOTH_SIDES = 3;
|
||||
COLLAPSE_TAGS = 4;
|
||||
COLLAPSE_NOTETYPES = 5;
|
||||
COLLAPSE_DECKS = 6;
|
||||
COLLAPSE_SAVED_SEARCHES = 7;
|
||||
COLLAPSE_TODAY = 8;
|
||||
COLLAPSE_CARD_STATE = 9;
|
||||
COLLAPSE_FLAGS = 10;
|
||||
SCHED_2021 = 11;
|
||||
ADDING_DEFAULTS_TO_CURRENT_DECK = 12;
|
||||
HIDE_AUDIO_PLAY_BUTTONS = 13;
|
||||
INTERRUPT_AUDIO_WHEN_ANSWERING = 14;
|
||||
PASTE_IMAGES_AS_PNG = 15;
|
||||
PASTE_STRIPS_FORMATTING = 16;
|
||||
NORMALIZE_NOTE_TEXT = 17;
|
||||
}
|
||||
enum String {
|
||||
SET_DUE_BROWSER = 0;
|
||||
SET_DUE_REVIEWER = 1;
|
||||
DEFAULT_SEARCH_TEXT = 2;
|
||||
CARD_STATE_CUSTOMIZER = 3;
|
||||
}
|
||||
}
|
||||
|
||||
message GetConfigBoolRequest {
|
||||
ConfigKey.Bool key = 1;
|
||||
}
|
||||
|
||||
message SetConfigBoolRequest {
|
||||
ConfigKey.Bool key = 1;
|
||||
bool value = 2;
|
||||
bool undoable = 3;
|
||||
}
|
||||
|
||||
message GetConfigStringRequest {
|
||||
ConfigKey.String key = 1;
|
||||
}
|
||||
|
||||
message SetConfigStringRequest {
|
||||
ConfigKey.String key = 1;
|
||||
string value = 2;
|
||||
bool undoable = 3;
|
||||
}
|
||||
|
||||
message OptionalStringConfigKey {
|
||||
ConfigKey.String key = 1;
|
||||
}
|
||||
|
||||
message SetConfigJsonRequest {
|
||||
string key = 1;
|
||||
bytes value_json = 2;
|
||||
bool undoable = 3;
|
||||
}
|
||||
|
||||
message Preferences {
|
||||
message Scheduling {
|
||||
enum NewReviewMix {
|
||||
DISTRIBUTE = 0;
|
||||
REVIEWS_FIRST = 1;
|
||||
NEW_FIRST = 2;
|
||||
}
|
||||
|
||||
// read only; 1-3
|
||||
uint32 scheduler_version = 1;
|
||||
|
||||
uint32 rollover = 2;
|
||||
uint32 learn_ahead_secs = 3;
|
||||
NewReviewMix new_review_mix = 4;
|
||||
|
||||
// v2 only
|
||||
bool new_timezone = 5;
|
||||
bool day_learn_first = 6;
|
||||
}
|
||||
message Reviewing {
|
||||
bool hide_audio_play_buttons = 1;
|
||||
bool interrupt_audio_when_answering = 2;
|
||||
bool show_remaining_due_counts = 3;
|
||||
bool show_intervals_on_buttons = 4;
|
||||
uint32 time_limit_secs = 5;
|
||||
}
|
||||
message Editing {
|
||||
bool adding_defaults_to_current_deck = 1;
|
||||
bool paste_images_as_png = 2;
|
||||
bool paste_strips_formatting = 3;
|
||||
string default_search_text = 4;
|
||||
}
|
||||
|
||||
Scheduling scheduling = 1;
|
||||
Reviewing reviewing = 2;
|
||||
Editing editing = 3;
|
||||
}
|
145
proto/anki/deckconfig.proto
Normal file
145
proto/anki/deckconfig.proto
Normal file
@ -0,0 +1,145 @@
|
||||
// Copyright: Ankitects Pty Ltd and contributors
|
||||
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
package anki.deckconfig;
|
||||
|
||||
import "anki/generic.proto";
|
||||
import "anki/collection.proto";
|
||||
import "anki/decks.proto";
|
||||
|
||||
service DeckConfigService {
|
||||
rpc AddOrUpdateDeckConfigLegacy(generic.Json) returns (DeckConfigId);
|
||||
rpc GetDeckConfig(DeckConfigId) returns (DeckConfig);
|
||||
rpc AllDeckConfigLegacy(generic.Empty) returns (generic.Json);
|
||||
rpc GetDeckConfigLegacy(DeckConfigId) returns (generic.Json);
|
||||
rpc NewDeckConfigLegacy(generic.Empty) returns (generic.Json);
|
||||
rpc RemoveDeckConfig(DeckConfigId) returns (generic.Empty);
|
||||
rpc GetDeckConfigsForUpdate(decks.DeckId) returns (DeckConfigsForUpdate);
|
||||
rpc UpdateDeckConfigs(UpdateDeckConfigsRequest)
|
||||
returns (collection.OpChanges);
|
||||
}
|
||||
|
||||
message DeckConfigId {
|
||||
int64 dcid = 1;
|
||||
}
|
||||
|
||||
message DeckConfig {
|
||||
message Config {
|
||||
enum NewCardInsertOrder {
|
||||
NEW_CARD_INSERT_ORDER_DUE = 0;
|
||||
NEW_CARD_INSERT_ORDER_RANDOM = 1;
|
||||
}
|
||||
enum NewCardGatherPriority {
|
||||
NEW_CARD_GATHER_PRIORITY_DECK = 0;
|
||||
NEW_CARD_GATHER_PRIORITY_LOWEST_POSITION = 1;
|
||||
NEW_CARD_GATHER_PRIORITY_HIGHEST_POSITION = 2;
|
||||
}
|
||||
enum NewCardSortOrder {
|
||||
NEW_CARD_SORT_ORDER_TEMPLATE_THEN_LOWEST_POSITION = 0;
|
||||
NEW_CARD_SORT_ORDER_TEMPLATE_THEN_HIGHEST_POSITION = 1;
|
||||
NEW_CARD_SORT_ORDER_TEMPLATE_THEN_RANDOM = 2;
|
||||
NEW_CARD_SORT_ORDER_LOWEST_POSITION = 3;
|
||||
NEW_CARD_SORT_ORDER_HIGHEST_POSITION = 4;
|
||||
NEW_CARD_SORT_ORDER_RANDOM = 5;
|
||||
}
|
||||
enum ReviewCardOrder {
|
||||
REVIEW_CARD_ORDER_DAY = 0;
|
||||
REVIEW_CARD_ORDER_DAY_THEN_DECK = 1;
|
||||
REVIEW_CARD_ORDER_DECK_THEN_DAY = 2;
|
||||
REVIEW_CARD_ORDER_INTERVALS_ASCENDING = 3;
|
||||
REVIEW_CARD_ORDER_INTERVALS_DESCENDING = 4;
|
||||
// REVIEW_CARD_ORDER_RELATIVE_OVERDUE = 3;
|
||||
}
|
||||
enum ReviewMix {
|
||||
REVIEW_MIX_MIX_WITH_REVIEWS = 0;
|
||||
REVIEW_MIX_AFTER_REVIEWS = 1;
|
||||
REVIEW_MIX_BEFORE_REVIEWS = 2;
|
||||
}
|
||||
enum LeechAction {
|
||||
LEECH_ACTION_SUSPEND = 0;
|
||||
LEECH_ACTION_TAG_ONLY = 1;
|
||||
}
|
||||
|
||||
repeated float learn_steps = 1;
|
||||
repeated float relearn_steps = 2;
|
||||
|
||||
reserved 3 to 8;
|
||||
|
||||
uint32 new_per_day = 9;
|
||||
uint32 reviews_per_day = 10;
|
||||
uint32 new_per_day_minimum = 29;
|
||||
|
||||
float initial_ease = 11;
|
||||
float easy_multiplier = 12;
|
||||
float hard_multiplier = 13;
|
||||
float lapse_multiplier = 14;
|
||||
float interval_multiplier = 15;
|
||||
|
||||
uint32 maximum_review_interval = 16;
|
||||
uint32 minimum_lapse_interval = 17;
|
||||
|
||||
uint32 graduating_interval_good = 18;
|
||||
uint32 graduating_interval_easy = 19;
|
||||
|
||||
NewCardInsertOrder new_card_insert_order = 20;
|
||||
NewCardGatherPriority new_card_gather_priority = 34;
|
||||
NewCardSortOrder new_card_sort_order = 32;
|
||||
ReviewMix new_mix = 30;
|
||||
|
||||
ReviewCardOrder review_order = 33;
|
||||
|
||||
ReviewMix interday_learning_mix = 31;
|
||||
|
||||
LeechAction leech_action = 21;
|
||||
uint32 leech_threshold = 22;
|
||||
|
||||
bool disable_autoplay = 23;
|
||||
uint32 cap_answer_time_to_secs = 24;
|
||||
bool show_timer = 25;
|
||||
bool skip_question_when_replaying_answer = 26;
|
||||
|
||||
bool bury_new = 27;
|
||||
bool bury_reviews = 28;
|
||||
|
||||
bytes other = 255;
|
||||
}
|
||||
|
||||
int64 id = 1;
|
||||
string name = 2;
|
||||
int64 mtime_secs = 3;
|
||||
int32 usn = 4;
|
||||
Config config = 5;
|
||||
}
|
||||
|
||||
message DeckConfigsForUpdate {
|
||||
message ConfigWithExtra {
|
||||
DeckConfig config = 1;
|
||||
uint32 use_count = 2;
|
||||
}
|
||||
message CurrentDeck {
|
||||
string name = 1;
|
||||
int64 config_id = 2;
|
||||
repeated int64 parent_config_ids = 3;
|
||||
}
|
||||
|
||||
repeated ConfigWithExtra all_config = 1;
|
||||
CurrentDeck current_deck = 2;
|
||||
DeckConfig defaults = 3;
|
||||
bool schema_modified = 4;
|
||||
bool v3_scheduler = 5;
|
||||
bool have_addons = 6;
|
||||
// only applies to v3 scheduler
|
||||
string card_state_customizer = 7;
|
||||
}
|
||||
|
||||
message UpdateDeckConfigsRequest {
|
||||
int64 target_deck_id = 1;
|
||||
/// Unchanged, non-selected configs can be omitted. Deck will
|
||||
/// be set to whichever entry comes last.
|
||||
repeated DeckConfig configs = 2;
|
||||
repeated int64 removed_config_ids = 3;
|
||||
bool apply_to_children = 4;
|
||||
string card_state_customizer = 5;
|
||||
}
|
188
proto/anki/decks.proto
Normal file
188
proto/anki/decks.proto
Normal file
@ -0,0 +1,188 @@
|
||||
// Copyright: Ankitects Pty Ltd and contributors
|
||||
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
package anki.decks;
|
||||
|
||||
import "anki/generic.proto";
|
||||
import "anki/collection.proto";
|
||||
|
||||
service DecksService {
|
||||
rpc AddDeckLegacy(generic.Json) returns (collection.OpChangesWithId);
|
||||
rpc AddOrUpdateDeckLegacy(AddOrUpdateDeckLegacyRequest) returns (DeckId);
|
||||
rpc DeckTree(DeckTreeRequest) returns (DeckTreeNode);
|
||||
rpc DeckTreeLegacy(generic.Empty) returns (generic.Json);
|
||||
rpc GetAllDecksLegacy(generic.Empty) returns (generic.Json);
|
||||
rpc GetDeckIdByName(generic.String) returns (DeckId);
|
||||
rpc GetDeck(DeckId) returns (Deck);
|
||||
rpc UpdateDeck(Deck) returns (collection.OpChanges);
|
||||
rpc UpdateDeckLegacy(generic.Json) returns (collection.OpChanges);
|
||||
rpc SetDeckCollapsed(SetDeckCollapsedRequest) returns (collection.OpChanges);
|
||||
rpc GetDeckLegacy(DeckId) returns (generic.Json);
|
||||
rpc GetDeckNames(GetDeckNamesRequest) returns (DeckNames);
|
||||
rpc NewDeckLegacy(generic.Bool) returns (generic.Json);
|
||||
rpc RemoveDecks(DeckIds) returns (collection.OpChangesWithCount);
|
||||
rpc ReparentDecks(ReparentDecksRequest)
|
||||
returns (collection.OpChangesWithCount);
|
||||
rpc RenameDeck(RenameDeckRequest) returns (collection.OpChanges);
|
||||
rpc GetOrCreateFilteredDeck(DeckId) returns (FilteredDeckForUpdate);
|
||||
rpc AddOrUpdateFilteredDeck(FilteredDeckForUpdate)
|
||||
returns (collection.OpChangesWithId);
|
||||
rpc FilteredDeckOrderLabels(generic.Empty) returns (generic.StringList);
|
||||
rpc SetCurrentDeck(DeckId) returns (collection.OpChanges);
|
||||
rpc GetCurrentDeck(generic.Empty) returns (Deck);
|
||||
}
|
||||
|
||||
message DeckId {
|
||||
int64 did = 1;
|
||||
}
|
||||
|
||||
message DeckIds {
|
||||
repeated int64 dids = 1;
|
||||
}
|
||||
|
||||
message Deck {
|
||||
message Common {
|
||||
bool study_collapsed = 1;
|
||||
bool browser_collapsed = 2;
|
||||
|
||||
uint32 last_day_studied = 3;
|
||||
int32 new_studied = 4;
|
||||
int32 review_studied = 5;
|
||||
int32 milliseconds_studied = 7;
|
||||
|
||||
// previously set in the v1 scheduler,
|
||||
// but not currently used for anything
|
||||
int32 learning_studied = 6;
|
||||
|
||||
reserved 8 to 13;
|
||||
|
||||
bytes other = 255;
|
||||
}
|
||||
message Normal {
|
||||
int64 config_id = 1;
|
||||
uint32 extend_new = 2;
|
||||
uint32 extend_review = 3;
|
||||
string description = 4;
|
||||
bool markdown_description = 5;
|
||||
|
||||
reserved 6 to 11;
|
||||
}
|
||||
message Filtered {
|
||||
message SearchTerm {
|
||||
enum Order {
|
||||
OLDEST_REVIEWED_FIRST = 0;
|
||||
RANDOM = 1;
|
||||
INTERVALS_ASCENDING = 2;
|
||||
INTERVALS_DESCENDING = 3;
|
||||
LAPSES = 4;
|
||||
ADDED = 5;
|
||||
DUE = 6;
|
||||
REVERSE_ADDED = 7;
|
||||
DUE_PRIORITY = 8;
|
||||
}
|
||||
|
||||
string search = 1;
|
||||
uint32 limit = 2;
|
||||
Order order = 3;
|
||||
}
|
||||
|
||||
bool reschedule = 1;
|
||||
repeated SearchTerm search_terms = 2;
|
||||
// v1 scheduler only
|
||||
repeated float delays = 3;
|
||||
// v2 scheduler only
|
||||
uint32 preview_delay = 4;
|
||||
}
|
||||
// a container to store the deck specifics in the DB
|
||||
// as a tagged enum
|
||||
message KindContainer {
|
||||
oneof kind {
|
||||
Normal normal = 1;
|
||||
Filtered filtered = 2;
|
||||
}
|
||||
}
|
||||
|
||||
int64 id = 1;
|
||||
string name = 2;
|
||||
int64 mtime_secs = 3;
|
||||
int32 usn = 4;
|
||||
Common common = 5;
|
||||
// the specifics are inlined here when sending data to clients,
|
||||
// as otherwise an extra level of indirection would be required
|
||||
oneof kind {
|
||||
Normal normal = 6;
|
||||
Filtered filtered = 7;
|
||||
}
|
||||
}
|
||||
|
||||
message AddOrUpdateDeckLegacyRequest {
|
||||
bytes deck = 1;
|
||||
bool preserve_usn_and_mtime = 2;
|
||||
}
|
||||
|
||||
message DeckTreeRequest {
|
||||
// if non-zero, counts for the provided timestamp will be included
|
||||
int64 now = 1;
|
||||
int64 top_deck_id = 2;
|
||||
}
|
||||
|
||||
message DeckTreeNode {
|
||||
int64 deck_id = 1;
|
||||
string name = 2;
|
||||
uint32 level = 4;
|
||||
bool collapsed = 5;
|
||||
|
||||
uint32 review_count = 6;
|
||||
uint32 learn_count = 7;
|
||||
uint32 new_count = 8;
|
||||
|
||||
bool filtered = 16;
|
||||
|
||||
// low index so key can be packed into a byte, but at bottom
|
||||
// to make debug output easier to read
|
||||
repeated DeckTreeNode children = 3;
|
||||
}
|
||||
|
||||
message SetDeckCollapsedRequest {
|
||||
enum Scope {
|
||||
REVIEWER = 0;
|
||||
BROWSER = 1;
|
||||
}
|
||||
|
||||
int64 deck_id = 1;
|
||||
bool collapsed = 2;
|
||||
Scope scope = 3;
|
||||
}
|
||||
|
||||
message GetDeckNamesRequest {
|
||||
bool skip_empty_default = 1;
|
||||
// if unset, implies skip_empty_default
|
||||
bool include_filtered = 2;
|
||||
}
|
||||
|
||||
message DeckNames {
|
||||
repeated DeckNameId entries = 1;
|
||||
}
|
||||
|
||||
message DeckNameId {
|
||||
int64 id = 1;
|
||||
string name = 2;
|
||||
}
|
||||
|
||||
message ReparentDecksRequest {
|
||||
repeated int64 deck_ids = 1;
|
||||
int64 new_parent = 2;
|
||||
}
|
||||
|
||||
message RenameDeckRequest {
|
||||
int64 deck_id = 1;
|
||||
string new_name = 2;
|
||||
}
|
||||
|
||||
message FilteredDeckForUpdate {
|
||||
int64 id = 1;
|
||||
string name = 2;
|
||||
Deck.Filtered config = 3;
|
||||
}
|
44
proto/anki/generic.proto
Normal file
44
proto/anki/generic.proto
Normal file
@ -0,0 +1,44 @@
|
||||
// Copyright: Ankitects Pty Ltd and contributors
|
||||
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
package anki.generic;
|
||||
|
||||
message Empty {}
|
||||
|
||||
message OptionalInt32 {
|
||||
sint32 val = 1;
|
||||
}
|
||||
|
||||
message OptionalUInt32 {
|
||||
uint32 val = 1;
|
||||
}
|
||||
|
||||
message Int32 {
|
||||
sint32 val = 1;
|
||||
}
|
||||
|
||||
message UInt32 {
|
||||
uint32 val = 1;
|
||||
}
|
||||
|
||||
message Int64 {
|
||||
int64 val = 1;
|
||||
}
|
||||
|
||||
message String {
|
||||
string val = 1;
|
||||
}
|
||||
|
||||
message Json {
|
||||
bytes json = 1;
|
||||
}
|
||||
|
||||
message Bool {
|
||||
bool val = 1;
|
||||
}
|
||||
|
||||
message StringList {
|
||||
repeated string vals = 1;
|
||||
}
|
42
proto/anki/i18n.proto
Normal file
42
proto/anki/i18n.proto
Normal file
@ -0,0 +1,42 @@
|
||||
// Copyright: Ankitects Pty Ltd and contributors
|
||||
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
package anki.i18n;
|
||||
|
||||
import "anki/generic.proto";
|
||||
|
||||
service I18nService {
|
||||
rpc TranslateString(TranslateStringRequest) returns (generic.String);
|
||||
rpc FormatTimespan(FormatTimespanRequest) returns (generic.String);
|
||||
rpc I18nResources(I18nResourcesRequest) returns (generic.Json);
|
||||
}
|
||||
|
||||
message TranslateStringRequest {
|
||||
uint32 module_index = 1;
|
||||
uint32 message_index = 2;
|
||||
map<string, TranslateArgValue> args = 3;
|
||||
}
|
||||
|
||||
message TranslateArgValue {
|
||||
oneof value {
|
||||
string str = 1;
|
||||
double number = 2;
|
||||
}
|
||||
}
|
||||
|
||||
message FormatTimespanRequest {
|
||||
enum Context {
|
||||
PRECISE = 0;
|
||||
ANSWER_BUTTONS = 1;
|
||||
INTERVALS = 2;
|
||||
}
|
||||
|
||||
float seconds = 1;
|
||||
Context context = 2;
|
||||
}
|
||||
|
||||
message I18nResourcesRequest {
|
||||
repeated string modules = 1;
|
||||
}
|
32
proto/anki/media.proto
Normal file
32
proto/anki/media.proto
Normal file
@ -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;
|
||||
}
|
106
proto/anki/notes.proto
Normal file
106
proto/anki/notes.proto
Normal file
@ -0,0 +1,106 @@
|
||||
// Copyright: Ankitects Pty Ltd and contributors
|
||||
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
package anki.notes;
|
||||
|
||||
import "anki/notetypes.proto";
|
||||
import "anki/collection.proto";
|
||||
import "anki/decks.proto";
|
||||
import "anki/cards.proto";
|
||||
|
||||
service NotesService {
|
||||
rpc NewNote(notetypes.NotetypeId) returns (Note);
|
||||
rpc AddNote(AddNoteRequest) returns (AddNoteResponse);
|
||||
rpc DefaultsForAdding(DefaultsForAddingRequest) returns (DeckAndNotetype);
|
||||
rpc DefaultDeckForNotetype(notetypes.NotetypeId) returns (decks.DeckId);
|
||||
rpc UpdateNote(UpdateNoteRequest) returns (collection.OpChanges);
|
||||
rpc GetNote(NoteId) returns (Note);
|
||||
rpc RemoveNotes(RemoveNotesRequest) returns (collection.OpChangesWithCount);
|
||||
rpc ClozeNumbersInNote(Note) returns (ClozeNumbersInNoteResponse);
|
||||
rpc AfterNoteUpdates(AfterNoteUpdatesRequest)
|
||||
returns (collection.OpChangesWithCount);
|
||||
rpc FieldNamesForNotes(FieldNamesForNotesRequest)
|
||||
returns (FieldNamesForNotesResponse);
|
||||
rpc NoteFieldsCheck(Note) returns (NoteFieldsCheckResponse);
|
||||
rpc CardsOfNote(NoteId) returns (cards.CardIds);
|
||||
rpc GetSingleNotetypeOfNotes(notes.NoteIds) returns (notetypes.NotetypeId);
|
||||
}
|
||||
|
||||
message NoteId {
|
||||
int64 nid = 1;
|
||||
}
|
||||
|
||||
message NoteIds {
|
||||
repeated int64 note_ids = 1;
|
||||
}
|
||||
|
||||
message Note {
|
||||
int64 id = 1;
|
||||
string guid = 2;
|
||||
int64 notetype_id = 3;
|
||||
uint32 mtime_secs = 4;
|
||||
int32 usn = 5;
|
||||
repeated string tags = 6;
|
||||
repeated string fields = 7;
|
||||
}
|
||||
|
||||
message AddNoteRequest {
|
||||
Note note = 1;
|
||||
int64 deck_id = 2;
|
||||
}
|
||||
|
||||
message AddNoteResponse {
|
||||
int64 note_id = 1;
|
||||
collection.OpChanges changes = 2;
|
||||
}
|
||||
|
||||
message UpdateNoteRequest {
|
||||
Note note = 1;
|
||||
bool skip_undo_entry = 2;
|
||||
}
|
||||
|
||||
message DefaultsForAddingRequest {
|
||||
int64 home_deck_of_current_review_card = 1;
|
||||
}
|
||||
|
||||
message DeckAndNotetype {
|
||||
int64 deck_id = 1;
|
||||
int64 notetype_id = 2;
|
||||
}
|
||||
|
||||
message RemoveNotesRequest {
|
||||
repeated int64 note_ids = 1;
|
||||
repeated int64 card_ids = 2;
|
||||
}
|
||||
|
||||
message ClozeNumbersInNoteResponse {
|
||||
repeated uint32 numbers = 1;
|
||||
}
|
||||
|
||||
message AfterNoteUpdatesRequest {
|
||||
repeated int64 nids = 1;
|
||||
bool mark_notes_modified = 2;
|
||||
bool generate_cards = 3;
|
||||
}
|
||||
|
||||
message FieldNamesForNotesRequest {
|
||||
repeated int64 nids = 1;
|
||||
}
|
||||
|
||||
message FieldNamesForNotesResponse {
|
||||
repeated string fields = 1;
|
||||
}
|
||||
|
||||
message NoteFieldsCheckResponse {
|
||||
enum State {
|
||||
NORMAL = 0;
|
||||
EMPTY = 1;
|
||||
DUPLICATE = 2;
|
||||
MISSING_CLOZE = 3;
|
||||
NOTETYPE_NOT_CLOZE = 4;
|
||||
FIELD_NOT_CLOZE = 5;
|
||||
}
|
||||
State state = 1;
|
||||
}
|
176
proto/anki/notetypes.proto
Normal file
176
proto/anki/notetypes.proto
Normal file
@ -0,0 +1,176 @@
|
||||
// Copyright: Ankitects Pty Ltd and contributors
|
||||
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
package anki.notetypes;
|
||||
|
||||
import "anki/generic.proto";
|
||||
import "anki/collection.proto";
|
||||
|
||||
service NotetypesService {
|
||||
rpc AddNotetype(Notetype) returns (collection.OpChangesWithId);
|
||||
rpc UpdateNotetype(Notetype) returns (collection.OpChanges);
|
||||
rpc AddNotetypeLegacy(generic.Json) returns (collection.OpChangesWithId);
|
||||
rpc UpdateNotetypeLegacy(generic.Json) returns (collection.OpChanges);
|
||||
rpc AddOrUpdateNotetype(AddOrUpdateNotetypeRequest) returns (NotetypeId);
|
||||
rpc GetStockNotetypeLegacy(StockNotetype) returns (generic.Json);
|
||||
rpc GetNotetype(NotetypeId) returns (Notetype);
|
||||
rpc GetNotetypeLegacy(NotetypeId) returns (generic.Json);
|
||||
rpc GetNotetypeNames(generic.Empty) returns (NotetypeNames);
|
||||
rpc GetNotetypeNamesAndCounts(generic.Empty) returns (NotetypeUseCounts);
|
||||
rpc GetNotetypeIdByName(generic.String) returns (NotetypeId);
|
||||
rpc RemoveNotetype(NotetypeId) returns (collection.OpChanges);
|
||||
rpc GetAuxNotetypeConfigKey(GetAuxConfigKeyRequest) returns (generic.String);
|
||||
rpc GetAuxTemplateConfigKey(GetAuxTemplateConfigKeyRequest)
|
||||
returns (generic.String);
|
||||
rpc GetChangeNotetypeInfo(GetChangeNotetypeInfoRequest)
|
||||
returns (ChangeNotetypeInfo);
|
||||
rpc ChangeNotetype(ChangeNotetypeRequest) returns (collection.OpChanges);
|
||||
}
|
||||
|
||||
message NotetypeId {
|
||||
int64 ntid = 1;
|
||||
}
|
||||
|
||||
message Notetype {
|
||||
message Config {
|
||||
enum Kind {
|
||||
KIND_NORMAL = 0;
|
||||
KIND_CLOZE = 1;
|
||||
}
|
||||
message CardRequirement {
|
||||
enum Kind {
|
||||
KIND_NONE = 0;
|
||||
KIND_ANY = 1;
|
||||
KIND_ALL = 2;
|
||||
}
|
||||
uint32 card_ord = 1;
|
||||
Kind kind = 2;
|
||||
repeated uint32 field_ords = 3;
|
||||
}
|
||||
|
||||
Kind kind = 1;
|
||||
uint32 sort_field_idx = 2;
|
||||
string css = 3;
|
||||
/// This is now stored separately; retrieve with DefaultsForAdding()
|
||||
int64 target_deck_id_unused = 4;
|
||||
string latex_pre = 5;
|
||||
string latex_post = 6;
|
||||
bool latex_svg = 7;
|
||||
repeated CardRequirement reqs = 8;
|
||||
|
||||
bytes other = 255;
|
||||
}
|
||||
message Field {
|
||||
message Config {
|
||||
bool sticky = 1;
|
||||
bool rtl = 2;
|
||||
string font_name = 3;
|
||||
uint32 font_size = 4;
|
||||
|
||||
bytes other = 255;
|
||||
}
|
||||
generic.OptionalUInt32 ord = 1;
|
||||
string name = 2;
|
||||
Config config = 5;
|
||||
}
|
||||
message Template {
|
||||
message Config {
|
||||
string q_format = 1;
|
||||
string a_format = 2;
|
||||
string q_format_browser = 3;
|
||||
string a_format_browser = 4;
|
||||
int64 target_deck_id = 5;
|
||||
string browser_font_name = 6;
|
||||
uint32 browser_font_size = 7;
|
||||
|
||||
bytes other = 255;
|
||||
}
|
||||
|
||||
generic.OptionalUInt32 ord = 1;
|
||||
string name = 2;
|
||||
int64 mtime_secs = 3;
|
||||
sint32 usn = 4;
|
||||
Config config = 5;
|
||||
}
|
||||
|
||||
int64 id = 1;
|
||||
string name = 2;
|
||||
int64 mtime_secs = 3;
|
||||
sint32 usn = 4;
|
||||
Config config = 7;
|
||||
repeated Field fields = 8;
|
||||
repeated Template templates = 9;
|
||||
}
|
||||
|
||||
message AddOrUpdateNotetypeRequest {
|
||||
bytes json = 1;
|
||||
bool preserve_usn_and_mtime = 2;
|
||||
}
|
||||
|
||||
message StockNotetype {
|
||||
enum Kind {
|
||||
BASIC = 0;
|
||||
BASIC_AND_REVERSED = 1;
|
||||
BASIC_OPTIONAL_REVERSED = 2;
|
||||
BASIC_TYPING = 3;
|
||||
CLOZE = 4;
|
||||
}
|
||||
|
||||
Kind kind = 1;
|
||||
}
|
||||
|
||||
message NotetypeNames {
|
||||
repeated NotetypeNameId entries = 1;
|
||||
}
|
||||
|
||||
message NotetypeUseCounts {
|
||||
repeated NotetypeNameIdUseCount entries = 1;
|
||||
}
|
||||
|
||||
message NotetypeNameId {
|
||||
int64 id = 1;
|
||||
string name = 2;
|
||||
}
|
||||
|
||||
message NotetypeNameIdUseCount {
|
||||
int64 id = 1;
|
||||
string name = 2;
|
||||
uint32 use_count = 3;
|
||||
}
|
||||
|
||||
message GetAuxConfigKeyRequest {
|
||||
int64 id = 1;
|
||||
string key = 2;
|
||||
}
|
||||
|
||||
message GetAuxTemplateConfigKeyRequest {
|
||||
int64 notetype_id = 1;
|
||||
uint32 card_ordinal = 2;
|
||||
string key = 3;
|
||||
}
|
||||
|
||||
message GetChangeNotetypeInfoRequest {
|
||||
int64 old_notetype_id = 1;
|
||||
int64 new_notetype_id = 2;
|
||||
}
|
||||
|
||||
message ChangeNotetypeRequest {
|
||||
repeated int64 note_ids = 1;
|
||||
// -1 is used to represent null, as nullable repeated fields
|
||||
// are unwieldy in protobuf
|
||||
repeated int32 new_fields = 2;
|
||||
repeated int32 new_templates = 3;
|
||||
int64 old_notetype_id = 4;
|
||||
int64 new_notetype_id = 5;
|
||||
int64 current_schema = 6;
|
||||
}
|
||||
|
||||
message ChangeNotetypeInfo {
|
||||
repeated string old_field_names = 1;
|
||||
repeated string old_template_names = 2;
|
||||
repeated string new_field_names = 3;
|
||||
repeated string new_template_names = 4;
|
||||
ChangeNotetypeRequest input = 5;
|
||||
}
|
219
proto/anki/scheduler.proto
Normal file
219
proto/anki/scheduler.proto
Normal file
@ -0,0 +1,219 @@
|
||||
// Copyright: Ankitects Pty Ltd and contributors
|
||||
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
package anki.scheduler;
|
||||
|
||||
import "anki/generic.proto";
|
||||
import "anki/cards.proto";
|
||||
import "anki/decks.proto";
|
||||
import "anki/collection.proto";
|
||||
import "anki/config.proto";
|
||||
|
||||
service SchedulerService {
|
||||
rpc GetQueuedCards(GetQueuedCardsRequest) returns (QueuedCards);
|
||||
rpc AnswerCard(CardAnswer) returns (collection.OpChanges);
|
||||
rpc SchedTimingToday(generic.Empty) returns (SchedTimingTodayResponse);
|
||||
rpc StudiedToday(generic.Empty) returns (generic.String);
|
||||
rpc StudiedTodayMessage(StudiedTodayMessageRequest) returns (generic.String);
|
||||
rpc UpdateStats(UpdateStatsRequest) returns (generic.Empty);
|
||||
rpc ExtendLimits(ExtendLimitsRequest) returns (generic.Empty);
|
||||
rpc CountsForDeckToday(decks.DeckId) returns (CountsForDeckTodayResponse);
|
||||
rpc CongratsInfo(generic.Empty) returns (CongratsInfoResponse);
|
||||
rpc RestoreBuriedAndSuspendedCards(cards.CardIds)
|
||||
returns (collection.OpChanges);
|
||||
rpc UnburyDeck(UnburyDeckRequest) returns (collection.OpChanges);
|
||||
rpc BuryOrSuspendCards(BuryOrSuspendCardsRequest)
|
||||
returns (collection.OpChangesWithCount);
|
||||
rpc EmptyFilteredDeck(decks.DeckId) returns (collection.OpChanges);
|
||||
rpc RebuildFilteredDeck(decks.DeckId) returns (collection.OpChangesWithCount);
|
||||
rpc ScheduleCardsAsNew(ScheduleCardsAsNewRequest)
|
||||
returns (collection.OpChanges);
|
||||
rpc SetDueDate(SetDueDateRequest) returns (collection.OpChanges);
|
||||
rpc SortCards(SortCardsRequest) returns (collection.OpChangesWithCount);
|
||||
rpc SortDeck(SortDeckRequest) returns (collection.OpChangesWithCount);
|
||||
rpc GetNextCardStates(cards.CardId) returns (NextCardStates);
|
||||
rpc DescribeNextStates(NextCardStates) returns (generic.StringList);
|
||||
rpc StateIsLeech(SchedulingState) returns (generic.Bool);
|
||||
rpc UpgradeScheduler(generic.Empty) returns (generic.Empty);
|
||||
}
|
||||
|
||||
message SchedulingState {
|
||||
message New {
|
||||
uint32 position = 1;
|
||||
}
|
||||
message Learning {
|
||||
uint32 remaining_steps = 1;
|
||||
uint32 scheduled_secs = 2;
|
||||
}
|
||||
message Review {
|
||||
uint32 scheduled_days = 1;
|
||||
uint32 elapsed_days = 2;
|
||||
float ease_factor = 3;
|
||||
uint32 lapses = 4;
|
||||
bool leeched = 5;
|
||||
}
|
||||
message Relearning {
|
||||
Review review = 1;
|
||||
Learning learning = 2;
|
||||
}
|
||||
message Normal {
|
||||
oneof value {
|
||||
New new = 1;
|
||||
Learning learning = 2;
|
||||
Review review = 3;
|
||||
Relearning relearning = 4;
|
||||
}
|
||||
}
|
||||
message Preview {
|
||||
uint32 scheduled_secs = 1;
|
||||
bool finished = 2;
|
||||
}
|
||||
message ReschedulingFilter {
|
||||
Normal original_state = 1;
|
||||
}
|
||||
message Filtered {
|
||||
oneof value {
|
||||
Preview preview = 1;
|
||||
ReschedulingFilter rescheduling = 2;
|
||||
}
|
||||
}
|
||||
|
||||
oneof value {
|
||||
Normal normal = 1;
|
||||
Filtered filtered = 2;
|
||||
}
|
||||
}
|
||||
|
||||
message QueuedCards {
|
||||
enum Queue {
|
||||
NEW = 0;
|
||||
LEARNING = 1;
|
||||
REVIEW = 2;
|
||||
}
|
||||
message QueuedCard {
|
||||
cards.Card card = 1;
|
||||
Queue queue = 2;
|
||||
NextCardStates next_states = 3;
|
||||
}
|
||||
|
||||
repeated QueuedCard cards = 1;
|
||||
uint32 new_count = 2;
|
||||
uint32 learning_count = 3;
|
||||
uint32 review_count = 4;
|
||||
}
|
||||
|
||||
message GetQueuedCardsRequest {
|
||||
uint32 fetch_limit = 1;
|
||||
bool intraday_learning_only = 2;
|
||||
}
|
||||
|
||||
message SchedTimingTodayResponse {
|
||||
uint32 days_elapsed = 1;
|
||||
int64 next_day_at = 2;
|
||||
}
|
||||
|
||||
message StudiedTodayMessageRequest {
|
||||
uint32 cards = 1;
|
||||
double seconds = 2;
|
||||
}
|
||||
|
||||
message UpdateStatsRequest {
|
||||
int64 deck_id = 1;
|
||||
int32 new_delta = 2;
|
||||
int32 review_delta = 4;
|
||||
int32 millisecond_delta = 5;
|
||||
}
|
||||
|
||||
message ExtendLimitsRequest {
|
||||
int64 deck_id = 1;
|
||||
int32 new_delta = 2;
|
||||
int32 review_delta = 3;
|
||||
}
|
||||
|
||||
message CountsForDeckTodayResponse {
|
||||
int32 new = 1;
|
||||
int32 review = 2;
|
||||
}
|
||||
|
||||
message CongratsInfoResponse {
|
||||
uint32 learn_remaining = 1;
|
||||
uint32 secs_until_next_learn = 2;
|
||||
bool review_remaining = 3;
|
||||
bool new_remaining = 4;
|
||||
bool have_sched_buried = 5;
|
||||
bool have_user_buried = 6;
|
||||
bool is_filtered_deck = 7;
|
||||
bool bridge_commands_supported = 8;
|
||||
string deck_description = 9;
|
||||
}
|
||||
|
||||
message UnburyDeckRequest {
|
||||
enum Mode {
|
||||
ALL = 0;
|
||||
SCHED_ONLY = 1;
|
||||
USER_ONLY = 2;
|
||||
}
|
||||
int64 deck_id = 1;
|
||||
Mode mode = 2;
|
||||
}
|
||||
|
||||
message BuryOrSuspendCardsRequest {
|
||||
enum Mode {
|
||||
SUSPEND = 0;
|
||||
BURY_SCHED = 1;
|
||||
BURY_USER = 2;
|
||||
}
|
||||
repeated int64 card_ids = 1;
|
||||
repeated int64 note_ids = 2;
|
||||
Mode mode = 3;
|
||||
}
|
||||
|
||||
message ScheduleCardsAsNewRequest {
|
||||
repeated int64 card_ids = 1;
|
||||
bool log = 2;
|
||||
}
|
||||
|
||||
message SetDueDateRequest {
|
||||
repeated int64 card_ids = 1;
|
||||
string days = 2;
|
||||
config.OptionalStringConfigKey config_key = 3;
|
||||
}
|
||||
|
||||
message SortCardsRequest {
|
||||
repeated int64 card_ids = 1;
|
||||
uint32 starting_from = 2;
|
||||
uint32 step_size = 3;
|
||||
bool randomize = 4;
|
||||
bool shift_existing = 5;
|
||||
}
|
||||
|
||||
message SortDeckRequest {
|
||||
int64 deck_id = 1;
|
||||
bool randomize = 2;
|
||||
}
|
||||
|
||||
message NextCardStates {
|
||||
SchedulingState current = 1;
|
||||
SchedulingState again = 2;
|
||||
SchedulingState hard = 3;
|
||||
SchedulingState good = 4;
|
||||
SchedulingState easy = 5;
|
||||
}
|
||||
|
||||
message CardAnswer {
|
||||
enum Rating {
|
||||
AGAIN = 0;
|
||||
HARD = 1;
|
||||
GOOD = 2;
|
||||
EASY = 3;
|
||||
}
|
||||
|
||||
int64 card_id = 1;
|
||||
SchedulingState current_state = 2;
|
||||
SchedulingState new_state = 3;
|
||||
Rating rating = 4;
|
||||
int64 answered_at_millis = 5;
|
||||
uint32 milliseconds_taken = 6;
|
||||
}
|
177
proto/anki/search.proto
Normal file
177
proto/anki/search.proto
Normal file
@ -0,0 +1,177 @@
|
||||
// Copyright: Ankitects Pty Ltd and contributors
|
||||
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
package anki.search;
|
||||
|
||||
import "anki/generic.proto";
|
||||
import "anki/collection.proto";
|
||||
|
||||
service SearchService {
|
||||
rpc BuildSearchString(SearchNode) returns (generic.String);
|
||||
rpc SearchCards(SearchRequest) returns (SearchResponse);
|
||||
rpc SearchNotes(SearchRequest) returns (SearchResponse);
|
||||
rpc JoinSearchNodes(JoinSearchNodesRequest) returns (generic.String);
|
||||
rpc ReplaceSearchNode(ReplaceSearchNodeRequest) returns (generic.String);
|
||||
rpc FindAndReplace(FindAndReplaceRequest)
|
||||
returns (collection.OpChangesWithCount);
|
||||
rpc AllBrowserColumns(generic.Empty) returns (BrowserColumns);
|
||||
rpc BrowserRowForId(generic.Int64) returns (BrowserRow);
|
||||
rpc SetActiveBrowserColumns(generic.StringList) returns (generic.Empty);
|
||||
}
|
||||
|
||||
message SearchNode {
|
||||
message Dupe {
|
||||
int64 notetype_id = 1;
|
||||
string first_field = 2;
|
||||
}
|
||||
enum Flag {
|
||||
FLAG_NONE = 0;
|
||||
FLAG_ANY = 1;
|
||||
FLAG_RED = 2;
|
||||
FLAG_ORANGE = 3;
|
||||
FLAG_GREEN = 4;
|
||||
FLAG_BLUE = 5;
|
||||
FLAG_PINK = 6;
|
||||
FLAG_TURQUOISE = 7;
|
||||
FLAG_PURPLE = 8;
|
||||
}
|
||||
enum Rating {
|
||||
RATING_ANY = 0;
|
||||
RATING_AGAIN = 1;
|
||||
RATING_HARD = 2;
|
||||
RATING_GOOD = 3;
|
||||
RATING_EASY = 4;
|
||||
RATING_BY_RESCHEDULE = 5;
|
||||
}
|
||||
message Rated {
|
||||
uint32 days = 1;
|
||||
Rating rating = 2;
|
||||
}
|
||||
enum CardState {
|
||||
CARD_STATE_NEW = 0;
|
||||
CARD_STATE_LEARN = 1;
|
||||
CARD_STATE_REVIEW = 2;
|
||||
CARD_STATE_DUE = 3;
|
||||
CARD_STATE_SUSPENDED = 4;
|
||||
CARD_STATE_BURIED = 5;
|
||||
}
|
||||
message IdList {
|
||||
repeated int64 ids = 1;
|
||||
}
|
||||
message Group {
|
||||
enum Joiner {
|
||||
AND = 0;
|
||||
OR = 1;
|
||||
}
|
||||
repeated SearchNode nodes = 1;
|
||||
Joiner joiner = 2;
|
||||
}
|
||||
oneof filter {
|
||||
Group group = 1;
|
||||
SearchNode negated = 2;
|
||||
string parsable_text = 3;
|
||||
uint32 template = 4;
|
||||
int64 nid = 5;
|
||||
Dupe dupe = 6;
|
||||
string field_name = 7;
|
||||
Rated rated = 8;
|
||||
uint32 added_in_days = 9;
|
||||
int32 due_in_days = 10;
|
||||
Flag flag = 11;
|
||||
CardState card_state = 12;
|
||||
IdList nids = 13;
|
||||
uint32 edited_in_days = 14;
|
||||
string deck = 15;
|
||||
int32 due_on_day = 16;
|
||||
string tag = 17;
|
||||
string note = 18;
|
||||
uint32 introduced_in_days = 19;
|
||||
}
|
||||
}
|
||||
|
||||
message SearchRequest {
|
||||
string search = 1;
|
||||
SortOrder order = 2;
|
||||
}
|
||||
|
||||
message SearchResponse {
|
||||
repeated int64 ids = 1;
|
||||
}
|
||||
|
||||
message SortOrder {
|
||||
message Builtin {
|
||||
string column = 1;
|
||||
bool reverse = 2;
|
||||
}
|
||||
oneof value {
|
||||
generic.Empty none = 1;
|
||||
string custom = 2;
|
||||
Builtin builtin = 3;
|
||||
}
|
||||
}
|
||||
|
||||
message JoinSearchNodesRequest {
|
||||
SearchNode.Group.Joiner joiner = 1;
|
||||
SearchNode existing_node = 2;
|
||||
SearchNode additional_node = 3;
|
||||
}
|
||||
|
||||
message ReplaceSearchNodeRequest {
|
||||
SearchNode existing_node = 1;
|
||||
SearchNode replacement_node = 2;
|
||||
}
|
||||
|
||||
message FindAndReplaceRequest {
|
||||
repeated int64 nids = 1;
|
||||
string search = 2;
|
||||
string replacement = 3;
|
||||
bool regex = 4;
|
||||
bool match_case = 5;
|
||||
string field_name = 6;
|
||||
}
|
||||
|
||||
message BrowserColumns {
|
||||
enum Sorting {
|
||||
SORTING_NONE = 0;
|
||||
SORTING_NORMAL = 1;
|
||||
SORTING_REVERSED = 2;
|
||||
}
|
||||
enum Alignment {
|
||||
ALIGNMENT_START = 0;
|
||||
ALIGNMENT_CENTER = 1;
|
||||
}
|
||||
message Column {
|
||||
string key = 1;
|
||||
string cards_mode_label = 2;
|
||||
string notes_mode_label = 3;
|
||||
Sorting sorting = 4;
|
||||
bool uses_cell_font = 5;
|
||||
Alignment alignment = 6;
|
||||
}
|
||||
repeated Column columns = 1;
|
||||
}
|
||||
|
||||
message BrowserRow {
|
||||
message Cell {
|
||||
string text = 1;
|
||||
bool is_rtl = 2;
|
||||
}
|
||||
enum Color {
|
||||
COLOR_DEFAULT = 0;
|
||||
COLOR_MARKED = 1;
|
||||
COLOR_SUSPENDED = 2;
|
||||
COLOR_FLAG_RED = 3;
|
||||
COLOR_FLAG_ORANGE = 4;
|
||||
COLOR_FLAG_GREEN = 5;
|
||||
COLOR_FLAG_BLUE = 6;
|
||||
COLOR_FLAG_PINK = 7;
|
||||
COLOR_FLAG_TURQUOISE = 8;
|
||||
COLOR_FLAG_PURPLE = 9;
|
||||
}
|
||||
repeated Cell cells = 1;
|
||||
Color color = 2;
|
||||
string font_name = 3;
|
||||
uint32 font_size = 4;
|
||||
}
|
64
proto/anki/stats.proto
Normal file
64
proto/anki/stats.proto
Normal file
@ -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;
|
||||
}
|
76
proto/anki/sync.proto
Normal file
76
proto/anki/sync.proto
Normal file
@ -0,0 +1,76 @@
|
||||
// Copyright: Ankitects Pty Ltd and contributors
|
||||
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
package anki.sync;
|
||||
|
||||
import "anki/generic.proto";
|
||||
|
||||
service SyncService {
|
||||
rpc SyncMedia(SyncAuth) returns (generic.Empty);
|
||||
rpc AbortSync(generic.Empty) returns (generic.Empty);
|
||||
rpc AbortMediaSync(generic.Empty) returns (generic.Empty);
|
||||
rpc BeforeUpload(generic.Empty) returns (generic.Empty);
|
||||
rpc SyncLogin(SyncLoginRequest) returns (SyncAuth);
|
||||
rpc SyncStatus(SyncAuth) returns (SyncStatusResponse);
|
||||
rpc SyncCollection(SyncAuth) returns (SyncCollectionResponse);
|
||||
rpc FullUpload(SyncAuth) returns (generic.Empty);
|
||||
rpc FullDownload(SyncAuth) returns (generic.Empty);
|
||||
rpc SyncServerMethod(SyncServerMethodRequest) returns (generic.Json);
|
||||
}
|
||||
|
||||
message SyncAuth {
|
||||
string hkey = 1;
|
||||
uint32 host_number = 2;
|
||||
}
|
||||
|
||||
message SyncLoginRequest {
|
||||
string username = 1;
|
||||
string password = 2;
|
||||
}
|
||||
|
||||
message SyncStatusResponse {
|
||||
enum Required {
|
||||
NO_CHANGES = 0;
|
||||
NORMAL_SYNC = 1;
|
||||
FULL_SYNC = 2;
|
||||
}
|
||||
Required required = 1;
|
||||
}
|
||||
|
||||
message SyncCollectionResponse {
|
||||
enum ChangesRequired {
|
||||
NO_CHANGES = 0;
|
||||
NORMAL_SYNC = 1;
|
||||
FULL_SYNC = 2;
|
||||
// local collection has no cards; upload not an option
|
||||
FULL_DOWNLOAD = 3;
|
||||
// remote collection has no cards; download not an option
|
||||
FULL_UPLOAD = 4;
|
||||
}
|
||||
|
||||
uint32 host_number = 1;
|
||||
string server_message = 2;
|
||||
ChangesRequired required = 3;
|
||||
}
|
||||
|
||||
message SyncServerMethodRequest {
|
||||
enum Method {
|
||||
HOST_KEY = 0;
|
||||
META = 1;
|
||||
START = 2;
|
||||
APPLY_GRAVES = 3;
|
||||
APPLY_CHANGES = 4;
|
||||
CHUNK = 5;
|
||||
APPLY_CHUNK = 6;
|
||||
SANITY_CHECK = 7;
|
||||
FINISH = 8;
|
||||
ABORT = 9;
|
||||
// caller must reopen after these two are called
|
||||
FULL_UPLOAD = 10;
|
||||
FULL_DOWNLOAD = 11;
|
||||
}
|
||||
Method method = 1;
|
||||
bytes data = 2;
|
||||
}
|
60
proto/anki/tags.proto
Normal file
60
proto/anki/tags.proto
Normal file
@ -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;
|
||||
}
|
@ -14,9 +14,9 @@ def _impl(rctx):
|
||||
alias(
|
||||
name = "clang_format",
|
||||
actual = select({
|
||||
"@net_ankiweb_anki//platforms:windows_x86_64": "@clang_format_windows_x86_64//:clang-format.exe",
|
||||
"@net_ankiweb_anki//platforms:macos_x86_64": "@clang_format_macos_x86_64//:clang-format",
|
||||
"@net_ankiweb_anki//platforms:linux_x86_64": "@clang_format_linux_x86_64//:clang-format",
|
||||
"@ankidesktop//platforms:windows_x86_64": "@clang_format_windows_x86_64//:clang-format.exe",
|
||||
"@ankidesktop//platforms:macos_x86_64": "@clang_format_macos_x86_64//:clang-format",
|
||||
"@ankidesktop//platforms:linux_x86_64": "@clang_format_linux_x86_64//:clang-format",
|
||||
}),
|
||||
visibility = ["//visibility:public"]
|
||||
)
|
||||
@ -68,7 +68,7 @@ def proto_format(name, srcs, **kwargs):
|
||||
py_test(
|
||||
name = name,
|
||||
srcs = [
|
||||
"proto_format.py",
|
||||
"@ankidesktop//proto:format.py",
|
||||
],
|
||||
data = ["@clang_format//:clang_format"] + srcs,
|
||||
args = ["$(location @clang_format//:clang_format)"] + [native.package_name() + "/" + f for f in srcs],
|
76
proto/format.bzl
Normal file
76
proto/format.bzl
Normal file
@ -0,0 +1,76 @@
|
||||
# Copyright: Ankitects Pty Ltd and contributors
|
||||
# License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||
|
||||
"""
|
||||
Exposes a clang-format binary for formatting protobuf.
|
||||
"""
|
||||
|
||||
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
|
||||
load("@bazel_tools//tools/build_defs/repo:utils.bzl", "maybe")
|
||||
load("@rules_python//python:defs.bzl", "py_test")
|
||||
|
||||
def _impl(rctx):
|
||||
rctx.file("BUILD.bazel", """
|
||||
alias(
|
||||
name = "clang_format",
|
||||
actual = select({
|
||||
"@ankidesktop//platforms:windows_x86_64": "@clang_format_windows_x86_64//:clang-format.exe",
|
||||
"@ankidesktop//platforms:macos_x86_64": "@clang_format_macos_x86_64//:clang-format",
|
||||
"@ankidesktop//platforms:linux_x86_64": "@clang_format_linux_x86_64//:clang-format",
|
||||
}),
|
||||
visibility = ["//visibility:public"]
|
||||
)
|
||||
""")
|
||||
|
||||
_setup_clang_format = repository_rule(
|
||||
attrs = {},
|
||||
local = True,
|
||||
implementation = _impl,
|
||||
)
|
||||
|
||||
def setup_clang_format(name):
|
||||
maybe(
|
||||
http_archive,
|
||||
name = "clang_format_macos_x86_64",
|
||||
build_file_content = """exports_files(["clang-format"])""",
|
||||
sha256 = "238be68d9478163a945754f06a213483473044f5a004c4125d3d9d8d3556466e",
|
||||
urls = [
|
||||
"https://github.com/ankitects/clang-format-binaries/releases/download/anki-2021-01-09/clang-format_macos_x86_64.zip",
|
||||
],
|
||||
)
|
||||
|
||||
maybe(
|
||||
http_archive,
|
||||
name = "clang_format_linux_x86_64",
|
||||
build_file_content = """exports_files(["clang-format"])""",
|
||||
sha256 = "64060bc4dbca30d0d96aab9344e2783008b16e1cae019a2532f1126ca5ec5449",
|
||||
urls = [
|
||||
"https://github.com/ankitects/clang-format-binaries/releases/download/anki-2021-01-09/clang-format_linux_x86_64.zip",
|
||||
],
|
||||
)
|
||||
|
||||
maybe(
|
||||
http_archive,
|
||||
name = "clang_format_windows_x86_64",
|
||||
build_file_content = """exports_files(["clang-format.exe"])""",
|
||||
sha256 = "7d9f6915e3f0fb72407830f0fc37141308d2e6915daba72987a52f309fbeaccc",
|
||||
urls = [
|
||||
"https://github.com/ankitects/clang-format-binaries/releases/download/anki-2021-01-09/clang-format_windows_x86_64.zip",
|
||||
],
|
||||
)
|
||||
|
||||
if not native.existing_rule(name):
|
||||
_setup_clang_format(
|
||||
name = name,
|
||||
)
|
||||
|
||||
def proto_format(name, srcs, **kwargs):
|
||||
py_test(
|
||||
name = name,
|
||||
srcs = [
|
||||
"@ankidesktop//format.py",
|
||||
],
|
||||
data = ["@clang_format//:clang_format"] + srcs,
|
||||
args = ["$(location @clang_format//:clang_format)"] + [native.package_name() + "/" + f for f in srcs],
|
||||
**kwargs
|
||||
)
|
@ -12,10 +12,10 @@ def _impl(rctx):
|
||||
alias(
|
||||
name = "protoc",
|
||||
actual = select({
|
||||
"@net_ankiweb_anki//platforms:windows_x86_64": "@protoc_bin_windows//:bin/protoc.exe",
|
||||
"@net_ankiweb_anki//platforms:macos_x86_64": "@protoc_bin_macos//:bin/protoc",
|
||||
"@net_ankiweb_anki//platforms:linux_x86_64": "@protoc_bin_linux_x86_64//:bin/protoc",
|
||||
"@net_ankiweb_anki//platforms:linux_arm64": "@protoc_bin_linux_arm64//:bin/protoc"
|
||||
"@ankidesktop//platforms:windows_x86_64": "@protoc_bin_windows//:bin/protoc.exe",
|
||||
"@ankidesktop//platforms:macos_x86_64": "@protoc_bin_macos//:bin/protoc",
|
||||
"@ankidesktop//platforms:linux_x86_64": "@protoc_bin_linux_x86_64//:bin/protoc",
|
||||
"@ankidesktop//platforms:linux_arm64": "@protoc_bin_linux_arm64//:bin/protoc"
|
||||
}),
|
||||
visibility = ["//visibility:public"]
|
||||
)
|
@ -14,6 +14,7 @@ ignored-classes=
|
||||
NoteFieldsCheckResponse,
|
||||
BackendError,
|
||||
SetDeckCollapsedRequest,
|
||||
ConfigKey,
|
||||
|
||||
[REPORTS]
|
||||
output-format=colorized
|
||||
|
@ -31,6 +31,7 @@ py_test(
|
||||
main = "tests/run_mypy.py",
|
||||
deps = [
|
||||
"//pylib/anki",
|
||||
"//pylib/anki:proto",
|
||||
requirement("mypy"),
|
||||
],
|
||||
)
|
||||
|
@ -4,6 +4,7 @@ load("@py_deps//:requirements.bzl", "requirement")
|
||||
load("@rules_python//experimental/python:wheel.bzl", "py_package", "py_wheel")
|
||||
load("//:defs.bzl", "anki_version")
|
||||
load("//pylib:orjson.bzl", "orjson_if_available")
|
||||
load("//pylib:protobuf.bzl", "py_proto")
|
||||
|
||||
copy_file(
|
||||
name = "buildinfo",
|
||||
@ -39,6 +40,7 @@ py_library(
|
||||
],
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
":proto",
|
||||
requirement("beautifulsoup4"),
|
||||
requirement("decorator"),
|
||||
requirement("distro"),
|
||||
@ -105,3 +107,24 @@ filegroup(
|
||||
"//pylib:__subpackages__",
|
||||
],
|
||||
)
|
||||
|
||||
py_proto(
|
||||
name = "proto_py",
|
||||
srcs = ["//proto"],
|
||||
visibility = [
|
||||
"//visibility:public",
|
||||
],
|
||||
)
|
||||
|
||||
py_library(
|
||||
name = "proto",
|
||||
srcs = [
|
||||
"__init__.py",
|
||||
# includes the .py files
|
||||
":proto_py",
|
||||
],
|
||||
# includes the .pyi files
|
||||
data = [":proto_py", "py.typed"],
|
||||
imports = [".."],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
@ -1,18 +1,2 @@
|
||||
# Copyright: Ankitects Pty Ltd and contributors
|
||||
# License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||
|
||||
import sys
|
||||
|
||||
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+")
|
||||
|
||||
# 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"]
|
||||
|
@ -1,27 +1,18 @@
|
||||
load("@rules_python//python:defs.bzl", "py_binary")
|
||||
load("@py_deps//:requirements.bzl", "requirement")
|
||||
load("//pylib:protobuf.bzl", "py_proto_library_typed")
|
||||
load("@bazel_skylib//rules:copy_file.bzl", "copy_file")
|
||||
load("@bazel_skylib//lib:selects.bzl", "selects")
|
||||
|
||||
py_proto_library_typed(
|
||||
name = "backend_pb2",
|
||||
src = "//rslib:backend.proto",
|
||||
visibility = [
|
||||
"//visibility:public",
|
||||
],
|
||||
)
|
||||
|
||||
py_binary(
|
||||
name = "genbackend",
|
||||
srcs = [
|
||||
"backend_pb2",
|
||||
"genbackend.py",
|
||||
],
|
||||
deps = [
|
||||
requirement("black"),
|
||||
requirement("stringcase"),
|
||||
requirement("protobuf"),
|
||||
"//pylib/anki:proto",
|
||||
],
|
||||
)
|
||||
|
||||
@ -94,7 +85,6 @@ filegroup(
|
||||
srcs = [
|
||||
"__init__.py",
|
||||
"rsbridge.pyi",
|
||||
":backend_pb2",
|
||||
":fluent_gen",
|
||||
":rsbackend_gen",
|
||||
":rsbridge",
|
||||
|
@ -11,6 +11,8 @@ from weakref import ref
|
||||
from markdown import markdown
|
||||
|
||||
import anki.buildinfo
|
||||
import anki.lang
|
||||
from anki import backend_pb2, i18n_pb2
|
||||
from anki._backend.generated import RustBackendGenerated
|
||||
from anki.dbproxy import Row as DBRow
|
||||
from anki.dbproxy import ValueForDB
|
||||
@ -32,7 +34,6 @@ from ..errors import (
|
||||
TemplateError,
|
||||
UndoEmpty,
|
||||
)
|
||||
from . import backend_pb2 as pb
|
||||
from . import rsbridge
|
||||
from .fluent import GeneratedTranslations, LegacyTranslationEnum
|
||||
|
||||
@ -65,7 +66,7 @@ class RustBackend(RustBackendGenerated):
|
||||
if langs is None:
|
||||
langs = [anki.lang.currentLang]
|
||||
|
||||
init_msg = pb.BackendInit(
|
||||
init_msg = backend_pb2.BackendInit(
|
||||
preferred_langs=langs,
|
||||
server=server,
|
||||
)
|
||||
@ -95,7 +96,7 @@ class RustBackend(RustBackendGenerated):
|
||||
return from_json_bytes(self._backend.db_command(to_json_bytes(input)))
|
||||
except Exception as e:
|
||||
err_bytes = bytes(e.args[0])
|
||||
err = pb.BackendError()
|
||||
err = backend_pb2.BackendError()
|
||||
err.ParseFromString(err_bytes)
|
||||
raise backend_exception_to_pylib(err)
|
||||
|
||||
@ -125,21 +126,21 @@ class RustBackend(RustBackendGenerated):
|
||||
return self._backend.command(service, method, input_bytes)
|
||||
except Exception as e:
|
||||
err_bytes = bytes(e.args[0])
|
||||
err = pb.BackendError()
|
||||
err = backend_pb2.BackendError()
|
||||
err.ParseFromString(err_bytes)
|
||||
raise backend_exception_to_pylib(err)
|
||||
|
||||
|
||||
def translate_string_in(
|
||||
module_index: int, message_index: int, **kwargs: Union[str, int, float]
|
||||
) -> pb.TranslateStringRequest:
|
||||
) -> i18n_pb2.TranslateStringRequest:
|
||||
args = {}
|
||||
for (k, v) in kwargs.items():
|
||||
if isinstance(v, str):
|
||||
args[k] = pb.TranslateArgValue(str=v)
|
||||
args[k] = i18n_pb2.TranslateArgValue(str=v)
|
||||
else:
|
||||
args[k] = pb.TranslateArgValue(number=v)
|
||||
return pb.TranslateStringRequest(
|
||||
args[k] = i18n_pb2.TranslateArgValue(number=v)
|
||||
return i18n_pb2.TranslateStringRequest(
|
||||
module_index=module_index, message_index=message_index, args=args
|
||||
)
|
||||
|
||||
@ -167,8 +168,8 @@ class Translations(GeneratedTranslations):
|
||||
)
|
||||
|
||||
|
||||
def backend_exception_to_pylib(err: pb.BackendError) -> Exception:
|
||||
kind = pb.BackendError
|
||||
def backend_exception_to_pylib(err: backend_pb2.BackendError) -> Exception:
|
||||
kind = backend_pb2.BackendError
|
||||
val = err.kind
|
||||
if val == kind.INTERRUPTED:
|
||||
return Interrupted()
|
||||
|
@ -1 +0,0 @@
|
||||
../../../bazel-bin/pylib/anki/_backend/backend_pb2.pyi
|
@ -7,7 +7,24 @@ import re
|
||||
import sys
|
||||
|
||||
import google.protobuf.descriptor
|
||||
import pylib.anki._backend.backend_pb2 as pb
|
||||
|
||||
import anki.backend_pb2
|
||||
import anki.i18n_pb2
|
||||
import anki.cards_pb2
|
||||
import anki.collection_pb2
|
||||
import anki.decks_pb2
|
||||
import anki.deckconfig_pb2
|
||||
import anki.notes_pb2
|
||||
import anki.notetypes_pb2
|
||||
import anki.scheduler_pb2
|
||||
import anki.sync_pb2
|
||||
import anki.config_pb2
|
||||
import anki.search_pb2
|
||||
import anki.stats_pb2
|
||||
import anki.card_rendering_pb2
|
||||
import anki.tags_pb2
|
||||
import anki.media_pb2
|
||||
|
||||
import stringcase
|
||||
|
||||
TYPE_DOUBLE = 1
|
||||
@ -73,11 +90,11 @@ def python_type_inner(field):
|
||||
raise Exception(f"unknown type: {type}")
|
||||
|
||||
|
||||
def fullname(fullname):
|
||||
if "FluentString" in fullname:
|
||||
return fullname.replace("BackendProto", "anki.fluent_pb2")
|
||||
else:
|
||||
return fullname.replace("BackendProto", "pb")
|
||||
def fullname(fullname: str) -> str:
|
||||
# eg anki.generic.Empty -> anki.generic_pb2.Empty
|
||||
components = fullname.split(".")
|
||||
components[1] += "_pb2"
|
||||
return ".".join(components)
|
||||
|
||||
|
||||
# get_deck_i_d -> get_deck_id etc
|
||||
@ -131,7 +148,7 @@ def render_method(service_idx, method_idx, method):
|
||||
return_type = python_type(f)
|
||||
else:
|
||||
single_field = ""
|
||||
return_type = f"pb.{method.output_type.name}"
|
||||
return_type = fullname(method.output_type.full_name)
|
||||
|
||||
if method.name in SKIP_DECODE:
|
||||
return_type = "bytes"
|
||||
@ -144,7 +161,7 @@ def render_method(service_idx, method_idx, method):
|
||||
buf += f"""return self._run_command({service_idx}, {method_idx}, input)
|
||||
"""
|
||||
else:
|
||||
buf += f"""output = pb.{method.output_type.name}()
|
||||
buf += f"""output = {fullname(method.output_type.full_name)}()
|
||||
output.ParseFromString(self._run_command({service_idx}, {method_idx}, input))
|
||||
return output{single_field}
|
||||
"""
|
||||
@ -162,12 +179,30 @@ def render_service(
|
||||
out.append(render_method(service_index, method_index, method))
|
||||
|
||||
|
||||
for service in pb.ServiceIndex.DESCRIPTOR.values:
|
||||
service_modules = dict(
|
||||
I18N=anki.i18n_pb2,
|
||||
COLLECTION=anki.collection_pb2,
|
||||
CARDS=anki.cards_pb2,
|
||||
NOTES=anki.notes_pb2,
|
||||
DECKS=anki.decks_pb2,
|
||||
DECK_CONFIG=anki.deckconfig_pb2,
|
||||
NOTETYPES=anki.notetypes_pb2,
|
||||
SCHEDULER=anki.scheduler_pb2,
|
||||
SYNC=anki.sync_pb2,
|
||||
CONFIG=anki.config_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
|
||||
service_var = (
|
||||
"_" + service.name.replace("SERVICE_INDEX", "").replace("_", "") + "SERVICE"
|
||||
)
|
||||
service_obj = getattr(pb, service_var)
|
||||
base = service.name.replace("SERVICE_INDEX_", "")
|
||||
service_pkg = service_modules.get(base)
|
||||
service_var = "_" + base.replace("_", "") + "SERVICE"
|
||||
service_obj = getattr(service_pkg, service_var)
|
||||
service_index = service.number
|
||||
render_service(service_obj, service_index)
|
||||
|
||||
@ -194,7 +229,23 @@ col.decks.all_config()
|
||||
|
||||
from typing import *
|
||||
|
||||
import anki._backend.backend_pb2 as pb
|
||||
import anki
|
||||
import anki.backend_pb2
|
||||
import anki.i18n_pb2
|
||||
import anki.cards_pb2
|
||||
import anki.collection_pb2
|
||||
import anki.decks_pb2
|
||||
import anki.deckconfig_pb2
|
||||
import anki.notes_pb2
|
||||
import anki.notetypes_pb2
|
||||
import anki.scheduler_pb2
|
||||
import anki.sync_pb2
|
||||
import anki.config_pb2
|
||||
import anki.search_pb2
|
||||
import anki.stats_pb2
|
||||
import anki.card_rendering_pb2
|
||||
import anki.tags_pb2
|
||||
import anki.media_pb2
|
||||
|
||||
class RustBackendGenerated:
|
||||
def _run_command(self, service: int, method: int, input: Any) -> bytes:
|
||||
|
1
pylib/anki/backend_pb2.pyi
Symbolic link
1
pylib/anki/backend_pb2.pyi
Symbolic link
@ -0,0 +1 @@
|
||||
../../bazel-bin/pylib/anki/backend_pb2.pyi
|
1
pylib/anki/card_rendering_pb2.pyi
Symbolic link
1
pylib/anki/card_rendering_pb2.pyi
Symbolic link
@ -0,0 +1 @@
|
||||
../../bazel-bin/pylib/anki/card_rendering_pb2.pyi
|
@ -10,8 +10,7 @@ import time
|
||||
from typing import List, NewType, Optional
|
||||
|
||||
import anki # pylint: disable=unused-import
|
||||
import anki._backend.backend_pb2 as _pb
|
||||
from anki import hooks
|
||||
from anki import cards_pb2, hooks
|
||||
from anki._legacy import DeprecatedNamesMixin, deprecated
|
||||
from anki.consts import *
|
||||
from anki.models import NotetypeDict, TemplateDict
|
||||
@ -31,7 +30,7 @@ from anki.sound import AVTag
|
||||
|
||||
# types
|
||||
CardId = NewType("CardId", int)
|
||||
BackendCard = _pb.Card
|
||||
BackendCard = cards_pb2.Card
|
||||
|
||||
|
||||
class Card(DeprecatedNamesMixin):
|
||||
@ -62,14 +61,14 @@ class Card(DeprecatedNamesMixin):
|
||||
self._load_from_backend_card(backend_card)
|
||||
else:
|
||||
# new card with defaults
|
||||
self._load_from_backend_card(_pb.Card())
|
||||
self._load_from_backend_card(cards_pb2.Card())
|
||||
|
||||
def load(self) -> None:
|
||||
card = self.col._backend.get_card(self.id)
|
||||
assert card
|
||||
self._load_from_backend_card(card)
|
||||
|
||||
def _load_from_backend_card(self, card: _pb.Card) -> None:
|
||||
def _load_from_backend_card(self, card: cards_pb2.Card) -> None:
|
||||
self._render_output = None
|
||||
self._note = None
|
||||
self.id = CardId(card.id)
|
||||
@ -91,9 +90,9 @@ class Card(DeprecatedNamesMixin):
|
||||
self.flags = card.flags
|
||||
self.data = card.data
|
||||
|
||||
def _to_backend_card(self) -> _pb.Card:
|
||||
def _to_backend_card(self) -> cards_pb2.Card:
|
||||
# mtime & usn are set by backend
|
||||
return _pb.Card(
|
||||
return cards_pb2.Card(
|
||||
id=self.id,
|
||||
note_id=self.nid,
|
||||
deck_id=self.did,
|
||||
|
1
pylib/anki/cards_pb2.pyi
Symbolic link
1
pylib/anki/cards_pb2.pyi
Symbolic link
@ -0,0 +1 @@
|
||||
../../bazel-bin/pylib/anki/cards_pb2.pyi
|
@ -7,24 +7,29 @@ from __future__ import annotations
|
||||
|
||||
from typing import Any, Generator, List, Literal, Optional, Sequence, Tuple, Union, cast
|
||||
|
||||
import anki._backend.backend_pb2 as _pb
|
||||
|
||||
# protobuf we publicly export - listed first to avoid circular imports
|
||||
from anki import (
|
||||
card_rendering_pb2,
|
||||
collection_pb2,
|
||||
config_pb2,
|
||||
generic_pb2,
|
||||
search_pb2,
|
||||
stats_pb2,
|
||||
)
|
||||
from anki._legacy import DeprecatedNamesMixin, deprecated
|
||||
|
||||
SearchNode = _pb.SearchNode
|
||||
Progress = _pb.Progress
|
||||
EmptyCardsReport = _pb.EmptyCardsReport
|
||||
GraphPreferences = _pb.GraphPreferences
|
||||
Preferences = _pb.Preferences
|
||||
UndoStatus = _pb.UndoStatus
|
||||
OpChanges = _pb.OpChanges
|
||||
OpChangesWithCount = _pb.OpChangesWithCount
|
||||
OpChangesWithId = _pb.OpChangesWithId
|
||||
OpChangesAfterUndo = _pb.OpChangesAfterUndo
|
||||
DefaultsForAdding = _pb.DeckAndNotetype
|
||||
BrowserRow = _pb.BrowserRow
|
||||
BrowserColumns = _pb.BrowserColumns
|
||||
# protobuf we publicly export - listed first to avoid circular imports
|
||||
SearchNode = search_pb2.SearchNode
|
||||
Progress = collection_pb2.Progress
|
||||
EmptyCardsReport = card_rendering_pb2.EmptyCardsReport
|
||||
GraphPreferences = stats_pb2.GraphPreferences
|
||||
Preferences = config_pb2.Preferences
|
||||
UndoStatus = collection_pb2.UndoStatus
|
||||
OpChanges = collection_pb2.OpChanges
|
||||
OpChangesWithCount = collection_pb2.OpChangesWithCount
|
||||
OpChangesWithId = collection_pb2.OpChangesWithId
|
||||
OpChangesAfterUndo = collection_pb2.OpChangesAfterUndo
|
||||
BrowserRow = search_pb2.BrowserRow
|
||||
BrowserColumns = search_pb2.BrowserColumns
|
||||
|
||||
import copy
|
||||
import os
|
||||
@ -370,7 +375,7 @@ class Collection(DeprecatedNamesMixin):
|
||||
|
||||
def defaults_for_adding(
|
||||
self, *, current_review_card: Optional[Card]
|
||||
) -> DefaultsForAdding:
|
||||
) -> anki.notes.DefaultsForAdding:
|
||||
"""Get starting deck and notetype for add screen.
|
||||
An option in the preferences controls whether this will be based on the current deck
|
||||
or current notetype.
|
||||
@ -487,12 +492,12 @@ class Collection(DeprecatedNamesMixin):
|
||||
order: Union[bool, str, BrowserColumns.Column],
|
||||
reverse: bool,
|
||||
finding_notes: bool,
|
||||
) -> _pb.SortOrder:
|
||||
) -> search_pb2.SortOrder:
|
||||
if isinstance(order, str):
|
||||
return _pb.SortOrder(custom=order)
|
||||
return search_pb2.SortOrder(custom=order)
|
||||
if isinstance(order, bool):
|
||||
if order is False:
|
||||
return _pb.SortOrder(none=_pb.Empty())
|
||||
return search_pb2.SortOrder(none=generic_pb2.Empty())
|
||||
# order=True: set args to sort column and reverse from config
|
||||
sort_key = BrowserConfig.sort_column_key(finding_notes)
|
||||
order = self.get_browser_column(self.get_config(sort_key))
|
||||
@ -500,13 +505,15 @@ class Collection(DeprecatedNamesMixin):
|
||||
reverse = self.get_config(reverse_key)
|
||||
if isinstance(order, BrowserColumns.Column):
|
||||
if order.sorting != BrowserColumns.SORTING_NONE:
|
||||
return _pb.SortOrder(
|
||||
builtin=_pb.SortOrder.Builtin(column=order.key, reverse=reverse)
|
||||
return search_pb2.SortOrder(
|
||||
builtin=search_pb2.SortOrder.Builtin(
|
||||
column=order.key, reverse=reverse
|
||||
)
|
||||
)
|
||||
|
||||
# eg, user is ordering on an add-on field with the add-on not installed
|
||||
print(f"{order} is not a valid sort order.")
|
||||
return _pb.SortOrder(none=_pb.Empty())
|
||||
return search_pb2.SortOrder(none=generic_pb2.Empty())
|
||||
|
||||
def find_and_replace(
|
||||
self,
|
||||
@ -725,19 +732,19 @@ class Collection(DeprecatedNamesMixin):
|
||||
"This is a debugging aid. Prefer .get_config() when you know the key you need."
|
||||
return from_json_bytes(self._backend.get_all_config())
|
||||
|
||||
def get_config_bool(self, key: Config.Bool.Key.V) -> bool:
|
||||
def get_config_bool(self, key: Config.Bool.V) -> bool:
|
||||
return self._backend.get_config_bool(key)
|
||||
|
||||
def set_config_bool(
|
||||
self, key: Config.Bool.Key.V, value: bool, *, undoable: bool = False
|
||||
self, key: Config.Bool.V, value: bool, *, undoable: bool = False
|
||||
) -> OpChanges:
|
||||
return self._backend.set_config_bool(key=key, value=value, undoable=undoable)
|
||||
|
||||
def get_config_string(self, key: Config.String.Key.V) -> str:
|
||||
def get_config_string(self, key: Config.String.V) -> str:
|
||||
return self._backend.get_config_string(key)
|
||||
|
||||
def set_config_string(
|
||||
self, key: Config.String.Key.V, value: str, undoable: bool = False
|
||||
self, key: Config.String.V, value: str, undoable: bool = False
|
||||
) -> OpChanges:
|
||||
return self._backend.set_config_string(key=key, value=value, undoable=undoable)
|
||||
|
||||
|
1
pylib/anki/collection_pb2.pyi
Symbolic link
1
pylib/anki/collection_pb2.pyi
Symbolic link
@ -0,0 +1 @@
|
||||
../../bazel-bin/pylib/anki/collection_pb2.pyi
|
@ -25,12 +25,12 @@ from typing import Any
|
||||
from weakref import ref
|
||||
|
||||
import anki
|
||||
from anki._backend import backend_pb2 as _pb
|
||||
from anki import config_pb2
|
||||
from anki.collection import OpChanges
|
||||
from anki.errors import NotFoundError
|
||||
from anki.utils import from_json_bytes, to_json_bytes
|
||||
|
||||
Config = _pb.Config
|
||||
Config = config_pb2.ConfigKey
|
||||
|
||||
|
||||
class ConfigManager:
|
||||
|
1
pylib/anki/config_pb2.pyi
Symbolic link
1
pylib/anki/config_pb2.pyi
Symbolic link
@ -0,0 +1 @@
|
||||
../../bazel-bin/pylib/anki/config_pb2.pyi
|
@ -6,8 +6,6 @@ from __future__ import annotations
|
||||
import sys
|
||||
from typing import Any, Dict, NewType, Optional
|
||||
|
||||
import anki
|
||||
|
||||
# whether new cards should be mixed with reviews, or shown first or last
|
||||
NEW_CARDS_DISTRIBUTE = 0
|
||||
NEW_CARDS_LAST = 1
|
||||
@ -93,6 +91,8 @@ REVLOG_RESCHED = 4
|
||||
# Labels
|
||||
##########################################################################
|
||||
|
||||
import anki.collection
|
||||
|
||||
|
||||
def _tr(col: Optional[anki.collection.Collection]) -> Any:
|
||||
if col:
|
||||
|
@ -7,7 +7,7 @@ import re
|
||||
from re import Match
|
||||
from typing import Any, Dict, Iterable, List, Optional, Sequence, Tuple, Union
|
||||
|
||||
import anki
|
||||
import anki._backend
|
||||
|
||||
# DBValue is actually Union[str, int, float, None], but if defined
|
||||
# that way, every call site needs to do a type check prior to using
|
||||
|
1
pylib/anki/deckconfig_pb2.pyi
Symbolic link
1
pylib/anki/deckconfig_pb2.pyi
Symbolic link
@ -0,0 +1 @@
|
||||
../../bazel-bin/pylib/anki/deckconfig_pb2.pyi
|
@ -23,7 +23,7 @@ from typing import (
|
||||
if TYPE_CHECKING:
|
||||
import anki
|
||||
|
||||
import anki._backend.backend_pb2 as _pb
|
||||
from anki import deckconfig_pb2, decks_pb2
|
||||
from anki._legacy import DeprecatedNamesMixin, deprecated, print_deprecation_warning
|
||||
from anki.cards import CardId
|
||||
from anki.collection import OpChanges, OpChangesWithCount, OpChangesWithId
|
||||
@ -32,12 +32,12 @@ from anki.errors import NotFoundError
|
||||
from anki.utils import from_json_bytes, ids2str, intTime, to_json_bytes
|
||||
|
||||
# public exports
|
||||
DeckTreeNode = _pb.DeckTreeNode
|
||||
DeckNameId = _pb.DeckNameId
|
||||
FilteredDeckConfig = _pb.Deck.Filtered
|
||||
DeckCollapseScope = _pb.SetDeckCollapsedRequest.Scope
|
||||
DeckConfigsForUpdate = _pb.DeckConfigsForUpdate
|
||||
UpdateDeckConfigs = _pb.UpdateDeckConfigsRequest
|
||||
DeckTreeNode = decks_pb2.DeckTreeNode
|
||||
DeckNameId = decks_pb2.DeckNameId
|
||||
FilteredDeckConfig = decks_pb2.Deck.Filtered
|
||||
DeckCollapseScope = decks_pb2.SetDeckCollapsedRequest.Scope
|
||||
DeckConfigsForUpdate = deckconfig_pb2.DeckConfigsForUpdate
|
||||
UpdateDeckConfigs = deckconfig_pb2.UpdateDeckConfigsRequest
|
||||
|
||||
# type aliases until we can move away from dicts
|
||||
DeckDict = Dict[str, Any]
|
||||
|
1
pylib/anki/decks_pb2.pyi
Symbolic link
1
pylib/anki/decks_pb2.pyi
Symbolic link
@ -0,0 +1 @@
|
||||
../../bazel-bin/pylib/anki/decks_pb2.pyi
|
1
pylib/anki/generic_pb2.pyi
Symbolic link
1
pylib/anki/generic_pb2.pyi
Symbolic link
@ -0,0 +1 @@
|
||||
../../bazel-bin/pylib/anki/generic_pb2.pyi
|
@ -76,7 +76,7 @@ class HttpClient:
|
||||
return buf.getvalue()
|
||||
|
||||
def _agentName(self) -> str:
|
||||
from anki import version
|
||||
from anki.buildinfo import version
|
||||
|
||||
return f"Anki {version}"
|
||||
|
||||
|
1
pylib/anki/i18n_pb2.pyi
Symbolic link
1
pylib/anki/i18n_pb2.pyi
Symbolic link
@ -0,0 +1 @@
|
||||
../../bazel-bin/pylib/anki/i18n_pb2.pyi
|
@ -3,7 +3,7 @@
|
||||
|
||||
from typing import Any, Callable, Sequence, Tuple, Type, Union
|
||||
|
||||
from anki import Collection
|
||||
from anki.collection import Collection
|
||||
from anki.importing.anki2 import Anki2Importer
|
||||
from anki.importing.apkg import AnkiPackageImporter
|
||||
from anki.importing.base import Importer
|
||||
|
@ -9,7 +9,8 @@ import weakref
|
||||
from typing import Optional, Tuple
|
||||
|
||||
import anki
|
||||
import anki._backend.backend_pb2 as _pb
|
||||
import anki._backend
|
||||
import anki.i18n_pb2 as _pb
|
||||
|
||||
# public exports
|
||||
TR = anki._backend.LegacyTranslationEnum
|
||||
|
@ -10,8 +10,7 @@ from dataclasses import dataclass
|
||||
from typing import Any, List, Optional, Tuple
|
||||
|
||||
import anki
|
||||
import anki._backend.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=[
|
||||
|
@ -10,8 +10,7 @@ import sys
|
||||
import time
|
||||
from typing import Any, Callable, List, Optional, Tuple
|
||||
|
||||
import anki
|
||||
import anki._backend.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
|
||||
|
1
pylib/anki/media_pb2.pyi
Symbolic link
1
pylib/anki/media_pb2.pyi
Symbolic link
@ -0,0 +1 @@
|
||||
../../bazel-bin/pylib/anki/media_pb2.pyi
|
@ -12,7 +12,7 @@ import time
|
||||
from typing import Any, Dict, List, NewType, Optional, Sequence, Tuple, Union
|
||||
|
||||
import anki # pylint: disable=unused-import
|
||||
import anki._backend.backend_pb2 as _pb
|
||||
from anki import notetypes_pb2
|
||||
from anki._legacy import DeprecatedNamesMixin, deprecated, print_deprecation_warning
|
||||
from anki.collection import OpChanges, OpChangesWithId
|
||||
from anki.consts import *
|
||||
@ -22,11 +22,11 @@ from anki.stdmodels import StockNotetypeKind
|
||||
from anki.utils import checksum, from_json_bytes, to_json_bytes
|
||||
|
||||
# public exports
|
||||
NotetypeNameId = _pb.NotetypeNameId
|
||||
NotetypeNameIdUseCount = _pb.NotetypeNameIdUseCount
|
||||
NotetypeNames = _pb.NotetypeNames
|
||||
ChangeNotetypeInfo = _pb.ChangeNotetypeInfo
|
||||
ChangeNotetypeRequest = _pb.ChangeNotetypeRequest
|
||||
NotetypeNameId = notetypes_pb2.NotetypeNameId
|
||||
NotetypeNameIdUseCount = notetypes_pb2.NotetypeNameIdUseCount
|
||||
NotetypeNames = notetypes_pb2.NotetypeNames
|
||||
ChangeNotetypeInfo = notetypes_pb2.ChangeNotetypeInfo
|
||||
ChangeNotetypeRequest = notetypes_pb2.ChangeNotetypeRequest
|
||||
|
||||
# legacy types
|
||||
NotetypeDict = Dict[str, Any]
|
||||
@ -459,7 +459,9 @@ and notes.mid = ? and cards.ord = ?""",
|
||||
def _availClozeOrds(
|
||||
self, notetype: NotetypeDict, flds: str, allow_empty: bool = True
|
||||
) -> List[int]:
|
||||
note = _pb.Note(fields=[flds])
|
||||
import anki.notes_pb2
|
||||
|
||||
note = anki.notes_pb2.Note(fields=[flds])
|
||||
return list(self.col._backend.cloze_numbers_in_note(note))
|
||||
|
||||
# @deprecated(replaced_by=add_template)
|
||||
|
@ -9,15 +9,15 @@ import copy
|
||||
from typing import Any, List, NewType, Optional, Sequence, Tuple, Union
|
||||
|
||||
import anki # pylint: disable=unused-import
|
||||
import anki._backend.backend_pb2 as _pb
|
||||
from anki import hooks
|
||||
from anki import hooks, notes_pb2
|
||||
from anki._legacy import DeprecatedNamesMixin
|
||||
from anki.consts import MODEL_STD
|
||||
from anki.models import NotetypeDict, NotetypeId, TemplateDict
|
||||
from anki.utils import joinFields
|
||||
|
||||
DuplicateOrEmptyResult = _pb.NoteFieldsCheckResponse.State
|
||||
NoteFieldsCheckResult = _pb.NoteFieldsCheckResponse.State
|
||||
DuplicateOrEmptyResult = notes_pb2.NoteFieldsCheckResponse.State
|
||||
NoteFieldsCheckResult = notes_pb2.NoteFieldsCheckResponse.State
|
||||
DefaultsForAdding = notes_pb2.DeckAndNotetype
|
||||
|
||||
# types
|
||||
NoteId = NewType("NoteId", int)
|
||||
@ -53,7 +53,7 @@ class Note(DeprecatedNamesMixin):
|
||||
assert note
|
||||
self._load_from_backend_note(note)
|
||||
|
||||
def _load_from_backend_note(self, note: _pb.Note) -> None:
|
||||
def _load_from_backend_note(self, note: notes_pb2.Note) -> None:
|
||||
self.id = NoteId(note.id)
|
||||
self.guid = note.guid
|
||||
self.mid = NotetypeId(note.notetype_id)
|
||||
@ -63,9 +63,9 @@ class Note(DeprecatedNamesMixin):
|
||||
self.fields = list(note.fields)
|
||||
self._fmap = self.col.models.field_map(self.note_type())
|
||||
|
||||
def _to_backend_note(self) -> _pb.Note:
|
||||
def _to_backend_note(self) -> notes_pb2.Note:
|
||||
hooks.note_will_flush(self)
|
||||
return _pb.Note(
|
||||
return notes_pb2.Note(
|
||||
id=self.id,
|
||||
guid=self.guid,
|
||||
notetype_id=self.mid,
|
||||
|
1
pylib/anki/notes_pb2.pyi
Symbolic link
1
pylib/anki/notes_pb2.pyi
Symbolic link
@ -0,0 +1 @@
|
||||
../../bazel-bin/pylib/anki/notes_pb2.pyi
|
1
pylib/anki/notetypes_pb2.pyi
Symbolic link
1
pylib/anki/notetypes_pb2.pyi
Symbolic link
@ -0,0 +1 @@
|
||||
../../bazel-bin/pylib/anki/notetypes_pb2.pyi
|
@ -4,26 +4,26 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import anki
|
||||
import anki._backend.backend_pb2 as _pb
|
||||
from anki import decks_pb2, scheduler_pb2
|
||||
from anki.collection import OpChanges, OpChangesWithCount, OpChangesWithId
|
||||
from anki.config import Config
|
||||
|
||||
SchedTimingToday = _pb.SchedTimingTodayResponse
|
||||
SchedTimingToday = scheduler_pb2.SchedTimingTodayResponse
|
||||
CongratsInfo = scheduler_pb2.CongratsInfoResponse
|
||||
UnburyDeck = scheduler_pb2.UnburyDeckRequest
|
||||
BuryOrSuspend = scheduler_pb2.BuryOrSuspendCardsRequest
|
||||
FilteredDeckForUpdate = decks_pb2.FilteredDeckForUpdate
|
||||
|
||||
|
||||
from typing import List, Optional, Sequence
|
||||
|
||||
from anki import config_pb2
|
||||
from anki.cards import CardId
|
||||
from anki.consts import CARD_TYPE_NEW, NEW_CARDS_RANDOM, QUEUE_TYPE_NEW, QUEUE_TYPE_REV
|
||||
from anki.decks import DeckConfigDict, DeckId, DeckTreeNode
|
||||
from anki.notes import NoteId
|
||||
from anki.utils import ids2str, intTime
|
||||
|
||||
CongratsInfo = _pb.CongratsInfoResponse
|
||||
UnburyDeck = _pb.UnburyDeckRequest
|
||||
BuryOrSuspend = _pb.BuryOrSuspendCardsRequest
|
||||
FilteredDeckForUpdate = _pb.FilteredDeckForUpdate
|
||||
|
||||
|
||||
class SchedulerBase:
|
||||
"Actions shared between schedulers."
|
||||
@ -162,14 +162,14 @@ select id from cards where did in %s and queue = {QUEUE_TYPE_REV} and due <= ? l
|
||||
self,
|
||||
card_ids: Sequence[CardId],
|
||||
days: str,
|
||||
config_key: Optional[Config.String.Key.V] = None,
|
||||
config_key: Optional[Config.String.V] = None,
|
||||
) -> OpChanges:
|
||||
"""Set cards to be due in `days`, turning them into review cards if necessary.
|
||||
`days` can be of the form '5' or '5..7'
|
||||
If `config_key` is provided, provided days will be remembered in config."""
|
||||
key: Optional[Config.String]
|
||||
key: Optional[config_pb2.OptionalStringConfigKey]
|
||||
if config_key is not None:
|
||||
key = Config.String(key=config_key)
|
||||
key = config_pb2.OptionalStringConfigKey(key=config_key)
|
||||
else:
|
||||
key = None
|
||||
return self.col._backend.set_due_date(
|
||||
|
@ -11,8 +11,7 @@ from heapq import *
|
||||
from typing import Any, Callable, Dict, List, Optional, Tuple, Union
|
||||
|
||||
import anki # pylint: disable=unused-import
|
||||
import anki._backend.backend_pb2 as _pb
|
||||
from anki import hooks
|
||||
from anki import hooks, scheduler_pb2
|
||||
from anki.cards import Card, CardId
|
||||
from anki.consts import *
|
||||
from anki.decks import DeckConfigDict, DeckDict, DeckId
|
||||
@ -20,8 +19,8 @@ from anki.lang import FormatTimeSpan
|
||||
from anki.scheduler.legacy import SchedulerBaseWithLegacy
|
||||
from anki.utils import ids2str, intTime
|
||||
|
||||
CountsForDeckToday = _pb.CountsForDeckTodayResponse
|
||||
SchedTimingToday = _pb.SchedTimingTodayResponse
|
||||
CountsForDeckToday = scheduler_pb2.CountsForDeckTodayResponse
|
||||
SchedTimingToday = scheduler_pb2.SchedTimingTodayResponse
|
||||
|
||||
# legacy type alias
|
||||
QueueConfig = Dict[str, Any]
|
||||
|
@ -14,7 +14,7 @@ from __future__ import annotations
|
||||
|
||||
from typing import List, Literal, Sequence, Tuple
|
||||
|
||||
import anki._backend.backend_pb2 as _pb
|
||||
from anki import scheduler_pb2
|
||||
from anki.cards import Card
|
||||
from anki.collection import OpChanges
|
||||
from anki.consts import *
|
||||
@ -24,10 +24,10 @@ from anki.scheduler.legacy import SchedulerBaseWithLegacy
|
||||
from anki.types import assert_exhaustive
|
||||
from anki.utils import intTime
|
||||
|
||||
QueuedCards = _pb.QueuedCards
|
||||
SchedulingState = _pb.SchedulingState
|
||||
NextStates = _pb.NextCardStates
|
||||
CardAnswer = _pb.CardAnswer
|
||||
QueuedCards = scheduler_pb2.QueuedCards
|
||||
SchedulingState = scheduler_pb2.SchedulingState
|
||||
NextStates = scheduler_pb2.NextCardStates
|
||||
CardAnswer = scheduler_pb2.CardAnswer
|
||||
|
||||
|
||||
class Scheduler(SchedulerBaseWithLegacy):
|
||||
@ -171,7 +171,7 @@ class Scheduler(SchedulerBaseWithLegacy):
|
||||
##########################################################################
|
||||
# fixme: move these into tests_schedv2 in the future
|
||||
|
||||
def _interval_for_state(self, state: _pb.SchedulingState) -> int:
|
||||
def _interval_for_state(self, state: scheduler_pb2.SchedulingState) -> int:
|
||||
kind = state.WhichOneof("value")
|
||||
if kind == "normal":
|
||||
return self._interval_for_normal_state(state.normal)
|
||||
@ -181,7 +181,9 @@ class Scheduler(SchedulerBaseWithLegacy):
|
||||
assert_exhaustive(kind)
|
||||
return 0 # unreachable
|
||||
|
||||
def _interval_for_normal_state(self, normal: _pb.SchedulingState.Normal) -> int:
|
||||
def _interval_for_normal_state(
|
||||
self, normal: scheduler_pb2.SchedulingState.Normal
|
||||
) -> int:
|
||||
kind = normal.WhichOneof("value")
|
||||
if kind == "new":
|
||||
return 0
|
||||
@ -196,7 +198,7 @@ class Scheduler(SchedulerBaseWithLegacy):
|
||||
return 0 # unreachable
|
||||
|
||||
def _interval_for_filtered_state(
|
||||
self, filtered: _pb.SchedulingState.Filtered
|
||||
self, filtered: scheduler_pb2.SchedulingState.Filtered
|
||||
) -> int:
|
||||
kind = filtered.WhichOneof("value")
|
||||
if kind == "preview":
|
||||
|
1
pylib/anki/scheduler_pb2.pyi
Symbolic link
1
pylib/anki/scheduler_pb2.pyi
Symbolic link
@ -0,0 +1 @@
|
||||
../../bazel-bin/pylib/anki/scheduler_pb2.pyi
|
1
pylib/anki/search_pb2.pyi
Symbolic link
1
pylib/anki/search_pb2.pyi
Symbolic link
@ -0,0 +1 @@
|
||||
../../bazel-bin/pylib/anki/search_pb2.pyi
|
@ -10,7 +10,8 @@ import json
|
||||
import time
|
||||
from typing import Any, Dict, List, Optional, Sequence, Tuple, Union
|
||||
|
||||
import anki
|
||||
import anki.cards
|
||||
import anki.collection
|
||||
from anki.consts import *
|
||||
from anki.lang import FormatTimeSpan
|
||||
from anki.utils import ids2str
|
||||
|
1
pylib/anki/stats_pb2.pyi
Symbolic link
1
pylib/anki/stats_pb2.pyi
Symbolic link
@ -0,0 +1 @@
|
||||
../../bazel-bin/pylib/anki/stats_pb2.pyi
|
@ -5,12 +5,13 @@ from __future__ import annotations
|
||||
|
||||
from typing import Any, Callable, List, Tuple
|
||||
|
||||
import anki
|
||||
import anki._backend.backend_pb2 as _pb
|
||||
import anki.collection
|
||||
import anki.models
|
||||
from anki import notetypes_pb2
|
||||
from anki.utils import from_json_bytes
|
||||
|
||||
# pylint: disable=no-member
|
||||
StockNotetypeKind = _pb.StockNotetype.Kind
|
||||
StockNotetypeKind = notetypes_pb2.StockNotetype.Kind
|
||||
|
||||
# add-on authors can add ("note type name", function)
|
||||
# to this list to have it shown in the add/clone note type screen
|
||||
|
@ -1,12 +1,12 @@
|
||||
# Copyright: Ankitects Pty Ltd and contributors
|
||||
# License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||
|
||||
import anki._backend.backend_pb2 as _pb
|
||||
from anki import sync_pb2
|
||||
|
||||
# public exports
|
||||
SyncAuth = _pb.SyncAuth
|
||||
SyncOutput = _pb.SyncCollectionResponse
|
||||
SyncStatus = _pb.SyncStatusResponse
|
||||
SyncAuth = sync_pb2.SyncAuth
|
||||
SyncOutput = sync_pb2.SyncCollectionResponse
|
||||
SyncStatus = sync_pb2.SyncStatusResponse
|
||||
|
||||
|
||||
# Legacy attributes some add-ons may be using
|
||||
|
1
pylib/anki/sync_pb2.pyi
Symbolic link
1
pylib/anki/sync_pb2.pyi
Symbolic link
@ -0,0 +1 @@
|
||||
../../bazel-bin/pylib/anki/sync_pb2.pyi
|
@ -26,8 +26,8 @@ except ImportError as e:
|
||||
|
||||
from flask import Response
|
||||
|
||||
from anki import Collection
|
||||
from anki._backend.backend_pb2 import SyncServerMethodRequest
|
||||
from anki.collection import Collection
|
||||
from anki.sync_pb2 import SyncServerMethodRequest
|
||||
|
||||
Method = SyncServerMethodRequest.Method # pylint: disable=no-member
|
||||
|
||||
|
@ -16,15 +16,15 @@ import re
|
||||
from typing import Collection, List, Match, Optional, Sequence
|
||||
|
||||
import anki # pylint: disable=unused-import
|
||||
import anki._backend.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"
|
||||
|
||||
|
||||
|
1
pylib/anki/tags_pb2.pyi
Symbolic link
1
pylib/anki/tags_pb2.pyi
Symbolic link
@ -0,0 +1 @@
|
||||
../../bazel-bin/pylib/anki/tags_pb2.pyi
|
@ -32,8 +32,7 @@ from dataclasses import dataclass
|
||||
from typing import Any, Dict, List, Optional, Sequence, Tuple, Union
|
||||
|
||||
import anki
|
||||
import anki._backend.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))
|
||||
|
||||
|
||||
|
@ -1,21 +1,21 @@
|
||||
load("@bazel_skylib//lib:paths.bzl", "paths")
|
||||
|
||||
def _py_proto_library_impl(ctx):
|
||||
basename = ctx.file.src.basename
|
||||
outs = [
|
||||
ctx.actions.declare_file(paths.replace_extension(basename, "_pb2.py")),
|
||||
ctx.actions.declare_file(paths.replace_extension(basename, "_pb2.pyi")),
|
||||
]
|
||||
def _py_proto_impl(ctx):
|
||||
outs = []
|
||||
for src in ctx.files.srcs:
|
||||
base = paths.basename(src.path)
|
||||
outs.append(ctx.actions.declare_file(paths.replace_extension(base, "_pb2.py")))
|
||||
outs.append(ctx.actions.declare_file(paths.replace_extension(base, "_pb2.pyi")))
|
||||
|
||||
ctx.actions.run(
|
||||
outputs = outs,
|
||||
inputs = [ctx.file.src],
|
||||
inputs = ctx.files.srcs,
|
||||
executable = ctx.executable.protoc_wrapper,
|
||||
arguments = [
|
||||
ctx.executable.protoc.path,
|
||||
ctx.executable.mypy_protobuf.path,
|
||||
ctx.file.src.path,
|
||||
paths.dirname(outs[0].path),
|
||||
],
|
||||
] + [file.path for file in ctx.files.srcs],
|
||||
tools = [
|
||||
ctx.executable.protoc,
|
||||
ctx.executable.mypy_protobuf,
|
||||
@ -26,10 +26,10 @@ def _py_proto_library_impl(ctx):
|
||||
DefaultInfo(files = depset(direct = outs), data_runfiles = ctx.runfiles(files = outs)),
|
||||
]
|
||||
|
||||
py_proto_library_typed = rule(
|
||||
implementation = _py_proto_library_impl,
|
||||
py_proto = rule(
|
||||
implementation = _py_proto_impl,
|
||||
attrs = {
|
||||
"src": attr.label(allow_single_file = [".proto"]),
|
||||
"srcs": attr.label_list(allow_files = [".proto"]),
|
||||
"protoc_wrapper": attr.label(
|
||||
executable = True,
|
||||
cfg = "exec",
|
||||
|
@ -6,7 +6,7 @@ import shutil
|
||||
import tempfile
|
||||
import time
|
||||
|
||||
from anki import Collection as aopen
|
||||
from anki.collection import Collection as aopen
|
||||
|
||||
# Between 2-4AM, shift the time back so test assumptions hold.
|
||||
lt = time.localtime()
|
||||
|
@ -6,7 +6,7 @@
|
||||
import os
|
||||
import tempfile
|
||||
|
||||
from anki import Collection as aopen
|
||||
from anki.collection import Collection as aopen
|
||||
from anki.dbproxy import emulate_named_args
|
||||
from anki.lang import TR, without_unicode_isolation
|
||||
from anki.stdmodels import addBasicModel, get_stock_notetypes
|
||||
|
@ -6,7 +6,7 @@
|
||||
import os
|
||||
import tempfile
|
||||
|
||||
from anki import Collection as aopen
|
||||
from anki.collection import Collection as aopen
|
||||
from anki.exporting import *
|
||||
from anki.importing import Anki2Importer
|
||||
from tests.shared import errorsAfterMidnight
|
||||
|
@ -4,7 +4,7 @@
|
||||
import copy
|
||||
import time
|
||||
|
||||
from anki import Collection
|
||||
from anki.collection import Collection
|
||||
from anki.consts import *
|
||||
from anki.lang import without_unicode_isolation
|
||||
from anki.utils import intTime
|
||||
|
@ -10,16 +10,12 @@ import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
(protoc, mypy_protobuf, proto, outdir) = sys.argv[1:]
|
||||
(protoc, mypy_protobuf, outdir, *protos) = sys.argv[1:]
|
||||
|
||||
# copy to current dir
|
||||
basename = os.path.basename(proto)
|
||||
shutil.copyfile(proto, basename)
|
||||
|
||||
# output filenames
|
||||
without_ext = os.path.splitext(basename)[0]
|
||||
pb2_py = without_ext + "_pb2.py"
|
||||
pb2_pyi = without_ext + "_pb2.pyi"
|
||||
if protos[0].startswith("external"):
|
||||
prefix = "external/ankidesktop/proto/"
|
||||
else:
|
||||
prefix = "proto/"
|
||||
|
||||
# invoke protoc
|
||||
subprocess.run(
|
||||
@ -28,13 +24,17 @@ subprocess.run(
|
||||
"--plugin=protoc-gen-mypy=" + mypy_protobuf,
|
||||
"--python_out=.",
|
||||
"--mypy_out=.",
|
||||
basename,
|
||||
"-I" + prefix,
|
||||
"-Iexternal/ankidesktop/" + prefix,
|
||||
*protos,
|
||||
],
|
||||
# mypy prints to stderr on success :-(
|
||||
stderr=subprocess.DEVNULL,
|
||||
check=True,
|
||||
)
|
||||
|
||||
# move files into output
|
||||
shutil.move(pb2_py, outdir + "/" + pb2_py)
|
||||
shutil.move(pb2_pyi, outdir + "/" + pb2_pyi)
|
||||
for proto in protos:
|
||||
without_prefix_and_ext, _ = os.path.splitext(proto[len(prefix) :])
|
||||
for ext in "_pb2.py", "_pb2.pyi":
|
||||
path = without_prefix_and_ext + ext
|
||||
shutil.move(path, os.path.join(outdir, os.path.basename(path)))
|
||||
|
@ -9,7 +9,7 @@ ignored-classes=
|
||||
BrowserColumns,
|
||||
BrowserRow,
|
||||
SearchNode,
|
||||
Config,
|
||||
ConfigKey,
|
||||
OpChanges,
|
||||
UnburyDeckRequest,
|
||||
CardAnswer,
|
||||
|
@ -13,13 +13,27 @@ import traceback
|
||||
from typing import Any, Callable, Dict, List, Optional, Tuple, Union, cast
|
||||
|
||||
import anki.lang
|
||||
from anki import version as _version
|
||||
from anki._backend import RustBackend
|
||||
from anki.buildinfo import version as _version
|
||||
from anki.collection import Collection
|
||||
from anki.consts import HELP_SITE
|
||||
from anki.utils import checksum, isLin, isMac
|
||||
from aqt.qt import *
|
||||
from aqt.utils import TR, locale_dir, tr
|
||||
|
||||
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
|
||||
|
||||
# compat aliases
|
||||
anki.version = _version # type: ignore
|
||||
anki.Collection = Collection # type: ignore
|
||||
|
||||
# we want to be able to print unicode debug info to console without
|
||||
# fear of a traceback on systems with the console set to ASCII
|
||||
try:
|
||||
|
@ -502,7 +502,7 @@ class SidebarTreeView(QTreeView):
|
||||
root: SidebarItem,
|
||||
name: str,
|
||||
icon: Union[str, ColoredIcon],
|
||||
collapse_key: Config.Bool.Key.V,
|
||||
collapse_key: Config.Bool.V,
|
||||
type: Optional[SidebarItemType] = None,
|
||||
) -> SidebarItem:
|
||||
def update(expanded: bool) -> None:
|
||||
|
6
qt/aqt/data/web/js/vendor/BUILD.bazel
vendored
6
qt/aqt/data/web/js/vendor/BUILD.bazel
vendored
@ -1,18 +1,15 @@
|
||||
load(
|
||||
"//ts:vendor.bzl",
|
||||
"copy_bootstrap_js",
|
||||
"copy_css_browser_selector",
|
||||
"copy_jquery",
|
||||
"copy_jquery_ui",
|
||||
"copy_protobufjs",
|
||||
"copy_bootstrap_js",
|
||||
)
|
||||
|
||||
copy_jquery(name = "jquery")
|
||||
|
||||
copy_jquery_ui(name = "jquery-ui")
|
||||
|
||||
copy_protobufjs(name = "protobufjs")
|
||||
|
||||
copy_css_browser_selector(name = "css-browser-selector")
|
||||
|
||||
copy_bootstrap_js(name = "bootstrap")
|
||||
@ -20,7 +17,6 @@ copy_bootstrap_js(name = "bootstrap")
|
||||
files = [
|
||||
"jquery",
|
||||
"jquery-ui",
|
||||
"protobufjs",
|
||||
"css-browser-selector",
|
||||
"bootstrap",
|
||||
]
|
||||
|
@ -137,7 +137,6 @@ class Editor:
|
||||
],
|
||||
js=[
|
||||
"js/vendor/jquery.min.js",
|
||||
"js/vendor/protobuf.min.js",
|
||||
"js/editor.js",
|
||||
],
|
||||
context=self,
|
||||
|
@ -6,7 +6,8 @@ from operator import itemgetter
|
||||
from typing import Any, List, Optional, Sequence
|
||||
|
||||
import aqt.clayout
|
||||
from anki import Collection, stdmodels
|
||||
from anki import stdmodels
|
||||
from anki.collection import Collection
|
||||
from anki.lang import without_unicode_isolation
|
||||
from anki.models import NotetypeDict, NotetypeId, NotetypeNameIdUseCount
|
||||
from anki.notes import Note
|
||||
|
@ -29,7 +29,7 @@ def set_due_date_dialog(
|
||||
*,
|
||||
parent: QWidget,
|
||||
card_ids: Sequence[CardId],
|
||||
config_key: Optional[Config.String.Key.V],
|
||||
config_key: Optional[Config.String.V],
|
||||
) -> Optional[CollectionOp[OpChanges]]:
|
||||
assert aqt.mw
|
||||
if not card_ids:
|
||||
|
@ -17,7 +17,7 @@ from send2trash import send2trash
|
||||
import anki.lang
|
||||
import aqt.forms
|
||||
import aqt.sound
|
||||
from anki import Collection
|
||||
from anki.collection import Collection
|
||||
from anki.db import DB
|
||||
from anki.lang import without_unicode_isolation
|
||||
from anki.sync import SyncAuth
|
||||
|
@ -293,7 +293,6 @@ class Reviewer:
|
||||
"js/mathjax.js",
|
||||
"js/vendor/mathjax/tex-chtml.js",
|
||||
"js/reviewer.js",
|
||||
"js/vendor/protobuf.min.js",
|
||||
"js/reviewer_extras.js",
|
||||
],
|
||||
context=self,
|
||||
|
@ -34,8 +34,8 @@ from PyQt5.QtWidgets import (
|
||||
)
|
||||
|
||||
import aqt
|
||||
from anki import Collection
|
||||
from anki._legacy import deprecated
|
||||
from anki.collection import Collection
|
||||
from anki.lang import TR, tr_legacyglobal # pylint: disable=unused-import
|
||||
from anki.utils import invalidFilename, isMac, isWin, noBundledLibs, versionWithBuild
|
||||
from aqt.qt import *
|
||||
|
@ -30,8 +30,8 @@ if subprocess.run(
|
||||
"--",
|
||||
"--config-file",
|
||||
"qt/mypy.ini",
|
||||
"bazel-bin/qt/dmypy.runfiles/net_ankiweb_anki/pylib/anki",
|
||||
"bazel-bin/qt/dmypy.runfiles/net_ankiweb_anki/qt/aqt",
|
||||
"bazel-bin/qt/dmypy.runfiles/ankidesktop/pylib/anki",
|
||||
"bazel-bin/qt/dmypy.runfiles/ankidesktop/qt/aqt",
|
||||
"--python-executable",
|
||||
os.path.abspath("pip/stubs/extendsitepkgs"),
|
||||
],
|
||||
|
@ -1,11 +1,9 @@
|
||||
# Copyright: Ankitects Pty Ltd and contributors
|
||||
# License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||
|
||||
load("@rules_proto//proto:defs.bzl", "proto_library")
|
||||
load("@rules_rust//rust:rust.bzl", "rust_binary", "rust_library", "rust_test")
|
||||
load("@rules_rust//cargo:cargo_build_script.bzl", "cargo_build_script")
|
||||
load(":rustfmt.bzl", "rustfmt_fix", "rustfmt_test")
|
||||
load(":clang_format.bzl", "proto_format")
|
||||
load("//ts:sql_format.bzl", "sql_format")
|
||||
|
||||
# Build script
|
||||
@ -15,7 +13,7 @@ cargo_build_script(
|
||||
name = "build_script",
|
||||
srcs = glob(["build/*.rs"]),
|
||||
build_script_env = {
|
||||
"BACKEND_PROTO": "$(location backend.proto)",
|
||||
"PROTO_TOP": "$(location //proto:.top_level)",
|
||||
"PROTOC": "$(location @com_google_protobuf//:protoc)",
|
||||
"RSLIB_FTL_ROOT": "$(location @rslib_ftl//:l10n.toml)",
|
||||
"EXTRA_FTL_ROOT": "$(location @extra_ftl//:l10n.toml)",
|
||||
@ -24,9 +22,10 @@ cargo_build_script(
|
||||
crate_root = "build/main.rs",
|
||||
data = [
|
||||
"//ftl",
|
||||
"backend.proto",
|
||||
"//proto",
|
||||
"@com_google_protobuf//:protoc",
|
||||
# bazel requires us to list these out separately
|
||||
"//proto:.top_level",
|
||||
"@rslib_ftl//:l10n.toml",
|
||||
"@extra_ftl//:l10n.toml",
|
||||
],
|
||||
@ -163,19 +162,3 @@ sql_format(
|
||||
name = "sql_format",
|
||||
srcs = glob(["**/*.sql"]),
|
||||
)
|
||||
|
||||
proto_format(
|
||||
name = "proto_format",
|
||||
srcs = ["backend.proto"],
|
||||
)
|
||||
|
||||
# backend.proto
|
||||
#######################
|
||||
|
||||
proto_library(
|
||||
name = "backend_proto_lib",
|
||||
srcs = ["backend.proto"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
exports_files(["backend.proto"])
|
||||
|
1681
rslib/backend.proto
1681
rslib/backend.proto
File diff suppressed because it is too large
Load Diff
@ -17,7 +17,7 @@ pub trait Service {
|
||||
write!(
|
||||
buf,
|
||||
concat!(" ",
|
||||
"{idx} => {{ let input = {input_type}::decode(input)?;\n",
|
||||
"{idx} => {{ let input = super::{input_type}::decode(input)?;\n",
|
||||
"let output = self.{rust_method}(input)?;\n",
|
||||
"let mut out_bytes = Vec::new(); output.encode(&mut out_bytes)?; Ok(out_bytes) }}, "),
|
||||
idx = idx,
|
||||
@ -38,8 +38,8 @@ pub trait Service {
|
||||
write!(
|
||||
buf,
|
||||
concat!(
|
||||
" fn {method_name}(&self, input: {input_type}) -> ",
|
||||
"Result<{output_type}>;\n"
|
||||
" fn {method_name}(&self, input: super::{input_type}) -> ",
|
||||
"Result<super::{output_type}>;\n"
|
||||
),
|
||||
method_name = method.name,
|
||||
input_type = method.input_type,
|
||||
@ -55,7 +55,6 @@ impl prost_build::ServiceGenerator for CustomGenerator {
|
||||
write!(
|
||||
buf,
|
||||
"pub mod {name}_service {{
|
||||
use super::*;
|
||||
use prost::Message;
|
||||
use crate::error::Result;
|
||||
",
|
||||
@ -73,16 +72,32 @@ fn service_generator() -> Box<dyn prost_build::ServiceGenerator> {
|
||||
|
||||
pub fn write_backend_proto_rs() {
|
||||
let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
|
||||
let backend_proto;
|
||||
let proto_dir;
|
||||
if let Ok(proto) = env::var("BACKEND_PROTO") {
|
||||
backend_proto = PathBuf::from(proto);
|
||||
proto_dir = backend_proto.parent().unwrap().to_owned();
|
||||
let proto_dir = if let Ok(proto) = env::var("PROTO_TOP") {
|
||||
let backend_proto = PathBuf::from(proto);
|
||||
backend_proto.parent().unwrap().to_owned()
|
||||
} else {
|
||||
backend_proto = PathBuf::from("backend.proto");
|
||||
proto_dir = PathBuf::from(".");
|
||||
PathBuf::from("../proto")
|
||||
};
|
||||
|
||||
let subfolders = &["anki"];
|
||||
let mut paths = vec![];
|
||||
|
||||
for subfolder in subfolders {
|
||||
for entry in proto_dir.join(subfolder).read_dir().unwrap() {
|
||||
let entry = entry.unwrap();
|
||||
let path = entry.path();
|
||||
if path
|
||||
.file_name()
|
||||
.unwrap()
|
||||
.to_str()
|
||||
.unwrap()
|
||||
.ends_with(".proto")
|
||||
{
|
||||
println!("cargo:rerun-if-changed={}", path.to_str().unwrap());
|
||||
paths.push(path);
|
||||
}
|
||||
}
|
||||
}
|
||||
println!("cargo:rerun-if-changed={}", backend_proto.to_str().unwrap());
|
||||
|
||||
let mut config = prost_build::Config::new();
|
||||
config
|
||||
@ -92,6 +107,6 @@ pub fn write_backend_proto_rs() {
|
||||
"Deck.Filtered.SearchTerm.Order",
|
||||
"#[derive(strum::EnumIter)]",
|
||||
)
|
||||
.compile_protos(&[&backend_proto], &[&proto_dir, &out_dir])
|
||||
.compile_protos(paths.as_slice(), &[proto_dir, out_dir])
|
||||
.unwrap();
|
||||
}
|
||||
|
@ -7,7 +7,7 @@ use super::Backend;
|
||||
pub(super) use crate::backend_proto::config_service::Service as ConfigService;
|
||||
use crate::{
|
||||
backend_proto as pb,
|
||||
backend_proto::config::{bool::Key as BoolKeyProto, string::Key as StringKeyProto},
|
||||
backend_proto::config_key::{Bool as BoolKeyProto, String as StringKeyProto},
|
||||
config::{BoolKey, StringKey},
|
||||
prelude::*,
|
||||
};
|
||||
@ -46,12 +46,6 @@ impl From<StringKeyProto> for StringKey {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<pb::config::String> for StringKey {
|
||||
fn from(key: pb::config::String) -> Self {
|
||||
key.key().into()
|
||||
}
|
||||
}
|
||||
|
||||
impl ConfigService for Backend {
|
||||
fn get_config_json(&self, input: pb::String) -> Result<pb::Json> {
|
||||
self.with_col(|col| {
|
||||
@ -91,7 +85,7 @@ impl ConfigService for Backend {
|
||||
.map(Into::into)
|
||||
}
|
||||
|
||||
fn get_config_bool(&self, input: pb::config::Bool) -> Result<pb::Bool> {
|
||||
fn get_config_bool(&self, input: pb::GetConfigBoolRequest) -> Result<pb::Bool> {
|
||||
self.with_col(|col| {
|
||||
Ok(pb::Bool {
|
||||
val: col.get_config_bool(input.key().into()),
|
||||
@ -104,7 +98,7 @@ impl ConfigService for Backend {
|
||||
.map(Into::into)
|
||||
}
|
||||
|
||||
fn get_config_string(&self, input: pb::config::String) -> Result<pb::String> {
|
||||
fn get_config_string(&self, input: pb::GetConfigStringRequest) -> Result<pb::String> {
|
||||
self.with_col(|col| {
|
||||
Ok(pb::String {
|
||||
val: col.get_config_string(input.key().into()),
|
||||
|
@ -48,7 +48,7 @@ use self::{
|
||||
notes::NotesService,
|
||||
notetypes::NotetypesService,
|
||||
progress::ProgressState,
|
||||
scheduler::SchedulingService,
|
||||
scheduler::SchedulerService,
|
||||
search::SearchService,
|
||||
stats::StatsService,
|
||||
sync::{SyncService, SyncState},
|
||||
@ -117,7 +117,7 @@ impl Backend {
|
||||
pb::ServiceIndex::from_i32(service as i32)
|
||||
.ok_or_else(|| AnkiError::invalid_input("invalid service"))
|
||||
.and_then(|service| match service {
|
||||
pb::ServiceIndex::Scheduling => SchedulingService::run_method(self, method, input),
|
||||
pb::ServiceIndex::Scheduler => SchedulerService::run_method(self, method, input),
|
||||
pb::ServiceIndex::Decks => DecksService::run_method(self, method, input),
|
||||
pb::ServiceIndex::Notes => NotesService::run_method(self, method, input),
|
||||
pb::ServiceIndex::Notetypes => NotetypesService::run_method(self, method, input),
|
||||
|
@ -143,6 +143,13 @@ impl NotesService for Backend {
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
fn get_single_notetype_of_notes(&self, input: pb::NoteIds) -> Result<pb::NotetypeId> {
|
||||
self.with_col(|col| {
|
||||
col.get_single_notetype_of_notes(&input.note_ids.into_newtype(NoteId))
|
||||
.map(Into::into)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn to_note_ids(ids: Vec<i64>) -> Vec<NoteId> {
|
||||
|
@ -159,13 +159,6 @@ impl NotetypesService for Backend {
|
||||
})
|
||||
}
|
||||
|
||||
fn get_single_notetype_of_notes(&self, input: pb::NoteIds) -> Result<pb::NotetypeId> {
|
||||
self.with_col(|col| {
|
||||
col.get_single_notetype_of_notes(&input.note_ids.into_newtype(NoteId))
|
||||
.map(Into::into)
|
||||
})
|
||||
}
|
||||
|
||||
fn get_change_notetype_info(
|
||||
&self,
|
||||
input: pb::GetChangeNotetypeInfoRequest,
|
||||
|
@ -5,7 +5,7 @@ mod answering;
|
||||
mod states;
|
||||
|
||||
use super::Backend;
|
||||
pub(super) use crate::backend_proto::scheduling_service::Service as SchedulingService;
|
||||
pub(super) use crate::backend_proto::scheduler_service::Service as SchedulerService;
|
||||
use crate::{
|
||||
backend_proto::{self as pb},
|
||||
prelude::*,
|
||||
@ -16,7 +16,7 @@ use crate::{
|
||||
stats::studied_today,
|
||||
};
|
||||
|
||||
impl SchedulingService for Backend {
|
||||
impl SchedulerService for Backend {
|
||||
/// This behaves like _updateCutoff() in older code - it also unburies at the start of
|
||||
/// a new day.
|
||||
fn sched_timing_today(&self, _input: pb::Empty) -> Result<pb::SchedTimingTodayResponse> {
|
||||
@ -117,7 +117,7 @@ impl SchedulingService for Backend {
|
||||
}
|
||||
|
||||
fn set_due_date(&self, input: pb::SetDueDateRequest) -> Result<pb::OpChanges> {
|
||||
let config = input.config_key.map(Into::into);
|
||||
let config = input.config_key.map(|v| v.key().into());
|
||||
let days = input.days;
|
||||
let cids = input.card_ids.into_newtype(CardId);
|
||||
self.with_col(|col| col.set_due_date(&cids, &days, config).map(Into::into))
|
||||
|
@ -1,4 +1,32 @@
|
||||
// Copyright: Ankitects Pty Ltd and contributors
|
||||
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||
|
||||
include!(concat!(env!("OUT_DIR"), "/backend_proto.rs"));
|
||||
macro_rules! protobuf {
|
||||
($ident:ident) => {
|
||||
pub mod $ident {
|
||||
include!(concat!(
|
||||
env!("OUT_DIR"),
|
||||
concat!("/anki.", stringify!($ident), ".rs")
|
||||
));
|
||||
}
|
||||
pub use $ident::*;
|
||||
};
|
||||
}
|
||||
|
||||
protobuf!(backend);
|
||||
protobuf!(card_rendering);
|
||||
protobuf!(cards);
|
||||
protobuf!(collection);
|
||||
protobuf!(config);
|
||||
protobuf!(deckconfig);
|
||||
protobuf!(decks);
|
||||
protobuf!(generic);
|
||||
protobuf!(i18n);
|
||||
protobuf!(media);
|
||||
protobuf!(notes);
|
||||
protobuf!(notetypes);
|
||||
protobuf!(scheduler);
|
||||
protobuf!(search);
|
||||
protobuf!(stats);
|
||||
protobuf!(sync);
|
||||
protobuf!(tags);
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user