From d24d2e33943af2361b5a9880572b30887efcf3ee Mon Sep 17 00:00:00 2001 From: Ranjit Odedra <78635944+ranjitodedra@users.noreply.github.com> Date: Fri, 17 Oct 2025 18:11:50 -0400 Subject: [PATCH 01/12] Fix sync login dialog not using newly-set custom sync server #4395 (#4396) * Fix sync login with custom server URL Call update_network() before showing login dialog to ensure the custom sync server URL is saved before attempting login. Previously, the custom URL was only saved when closing the preferences dialog, causing login to fail on first attempt. Fixes #4395 * Add contributor info --- CONTRIBUTORS | 1 + qt/aqt/preferences.py | 1 + 2 files changed, 2 insertions(+) diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 4e01aa0b2..43f7a7e46 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -251,6 +251,7 @@ Matbe766 Amanda Sternberg arold0 nav1s +Ranjit Odedra ******************** diff --git a/qt/aqt/preferences.py b/qt/aqt/preferences.py index afce6d489..939dd8c2c 100644 --- a/qt/aqt/preferences.py +++ b/qt/aqt/preferences.py @@ -260,6 +260,7 @@ class Preferences(QDialog): self.update_login_status() self.confirm_sync_after_login() + self.update_network() sync_login(self.mw, on_success) def sync_logout(self) -> None: From 9f9bafa66ca8cd51823d74a912c8b6bdb1d3adce Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 Oct 2025 18:30:23 +0700 Subject: [PATCH 02/12] Bump vite from 6.3.6 to 6.4.1 (#4405) Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) from 6.3.6 to 6.4.1. - [Release notes](https://github.com/vitejs/vite/releases) - [Changelog](https://github.com/vitejs/vite/blob/main/packages/vite/CHANGELOG.md) - [Commits](https://github.com/vitejs/vite/commits/create-vite@6.4.1/packages/vite) --- updated-dependencies: - dependency-name: vite dependency-version: 6.4.1 dependency-type: direct:development ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index 761f20972..bc1640152 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6939,8 +6939,8 @@ __metadata: linkType: hard "vite@npm:6": - version: 6.3.6 - resolution: "vite@npm:6.3.6" + version: 6.4.1 + resolution: "vite@npm:6.4.1" dependencies: esbuild: "npm:^0.25.0" fdir: "npm:^6.4.4" @@ -6989,7 +6989,7 @@ __metadata: optional: true bin: vite: bin/vite.js - checksum: 10c0/add701f1e72596c002275782e38d0389ab400c1be330c93a3009804d62db68097a936ca1c53c3301df3aaacfe5e328eab547060f31ef9c49a277ae50df6ad4fb + checksum: 10c0/77bb4c5b10f2a185e7859cc9a81c789021bc18009b02900347d1583b453b58e4b19ff07a5e5a5b522b68fc88728460bb45a63b104d969e8c6a6152aea3b849f7 languageName: node linkType: hard From 23263caea25fbe6e804c11b82b9765f952e9c515 Mon Sep 17 00:00:00 2001 From: llama Date: Mon, 27 Oct 2025 20:08:40 +0800 Subject: [PATCH 03/12] feat: show launcher if different version was installed (#4381) --- qt/launcher/build.rs | 3 +++ qt/launcher/src/main.rs | 18 +++++++++++++++++- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/qt/launcher/build.rs b/qt/launcher/build.rs index 3ba75b0e1..bc30f8dff 100644 --- a/qt/launcher/build.rs +++ b/qt/launcher/build.rs @@ -7,4 +7,7 @@ fn main() { .manifest_required() .unwrap(); } + println!("cargo:rerun-if-changed=../../out/buildhash"); + let buildhash = std::fs::read_to_string("../../out/buildhash").unwrap_or_default(); + println!("cargo:rustc-env=BUILDHASH={buildhash}"); } diff --git a/qt/launcher/src/main.rs b/qt/launcher/src/main.rs index 26fbe86a7..c350bcc14 100644 --- a/qt/launcher/src/main.rs +++ b/qt/launcher/src/main.rs @@ -152,7 +152,9 @@ fn run() -> Result<()> { let sync_time = file_timestamp_secs(&state.sync_complete_marker); state.pyproject_modified_by_user = pyproject_time > sync_time; let pyproject_has_changed = state.pyproject_modified_by_user; - if !launcher_requested && !pyproject_has_changed { + let different_launcher = diff_launcher_was_installed(&state)?; + + if !launcher_requested && !pyproject_has_changed && !different_launcher { // If no launcher request and venv is already up to date, launch Anki normally let args: Vec = std::env::args().skip(1).collect(); let cmd = build_python_command(&state, &args)?; @@ -1107,6 +1109,20 @@ fn show_mirror_submenu(state: &State) -> Result<()> { Ok(()) } +fn diff_launcher_was_installed(state: &State) -> Result { + let launcher_version = option_env!("BUILDHASH").unwrap_or("dev").trim(); + let launcher_version_path = state.uv_install_root.join("launcher-version"); + if let Ok(content) = read_file(&launcher_version_path) { + if let Ok(version_str) = String::from_utf8(content) { + if version_str.trim() == launcher_version { + return Ok(false); + } + } + } + write_file(launcher_version_path, launcher_version)?; + Ok(true) +} + #[cfg(test)] mod tests { use super::*; From a05c90cbce98b38a95d9813887d4c61a7146f146 Mon Sep 17 00:00:00 2001 From: llama Date: Mon, 27 Oct 2025 20:19:28 +0800 Subject: [PATCH 04/12] fix: make uv use system certstore (#4386) --- qt/launcher/src/main.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/qt/launcher/src/main.rs b/qt/launcher/src/main.rs index c350bcc14..117051fc7 100644 --- a/qt/launcher/src/main.rs +++ b/qt/launcher/src/main.rs @@ -1015,6 +1015,9 @@ fn uv_command(state: &State) -> Result { .env("UV_DEFAULT_INDEX", &pypi_mirror); } + // have uv use the system certstore instead of webpki-roots' + command.env("UV_NATIVE_TLS", "1"); + Ok(command) } From 62c950120cfd483f16e0263bb31ef8e2d95af5dc Mon Sep 17 00:00:00 2001 From: user1823 <92206575+user1823@users.noreply.github.com> Date: Mon, 27 Oct 2025 17:56:09 +0530 Subject: [PATCH 05/12] Fix(launcher)/Exclude pre-release if a newer major_minor exists (#4388) The current main produces a list like "25.09.2, 25.08b5, 25.07.5, 25.06b7, 25.02.7" Here, 25.08b5 and 25.06b7 should be filtered out for the same reason this code filters out the older patch releases. --- qt/launcher/src/main.rs | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/qt/launcher/src/main.rs b/qt/launcher/src/main.rs index 117051fc7..a399a3460 100644 --- a/qt/launcher/src/main.rs +++ b/qt/launcher/src/main.rs @@ -605,18 +605,27 @@ fn get_version_kind(state: &State) -> Result> { } fn with_only_latest_patch(versions: &[String]) -> Vec { - // Only show the latest patch release for a given (major, minor) + // Assumes versions are sorted in descending order (newest first) + // Only show the latest patch release for a given (major, minor), + // and exclude pre-releases if a newer major_minor exists let mut seen_major_minor = std::collections::HashSet::new(); versions .iter() .filter(|v| { - let (major, minor, _, _) = parse_version_for_filtering(v); + let (major, minor, _, is_prerelease) = parse_version_for_filtering(v); if major == 2 { return true; } let major_minor = (major, minor); if seen_major_minor.contains(&major_minor) { false + } else if is_prerelease + && seen_major_minor + .iter() + .any(|&(seen_major, seen_minor)| (seen_major, seen_minor) > (major, minor)) + { + // Exclude pre-release if a newer major_minor exists + false } else { seen_major_minor.insert(major_minor); true From d3ca0cd0b342a7178221493d2a0fb18a69ca7efd Mon Sep 17 00:00:00 2001 From: Abdo Date: Mon, 27 Oct 2025 15:27:50 +0300 Subject: [PATCH 06/12] Update PyCharm docs (#4389) * Add .idea.dist * Update PyCharm docs --- .idea.dist/repo.iml | 13 +++++++++++++ docs/editing.md | 14 +++++++++----- 2 files changed, 22 insertions(+), 5 deletions(-) create mode 100644 .idea.dist/repo.iml diff --git a/.idea.dist/repo.iml b/.idea.dist/repo.iml new file mode 100644 index 000000000..a9ec5ee1a --- /dev/null +++ b/.idea.dist/repo.iml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/docs/editing.md b/docs/editing.md index ba3fd6fce..42a92c5a8 100644 --- a/docs/editing.md +++ b/docs/editing.md @@ -46,10 +46,14 @@ see and install a number of recommended extensions. ## PyCharm/IntelliJ -If you decide to use PyCharm instead of VS Code, there are somethings to be -aware of. +### Setting up Python environment -### Pylib References +To make PyCharm recognize `anki` and `aqt` imports, you need to add source paths to _Settings > Project Structure_. +You can copy the provided .idea.dist directory to set up the paths automatically: -You'll need to use File>Project Structure to tell IntelliJ that pylib/ is a -sources root, so it knows references to 'anki' in aqt are valid. +``` +mkdir .idea && cd .idea +ln -sf ../.idea.dist/* . +``` + +You also need to add a new Python interpreter under _Settings > Python > Interpreter_ pointing to the Python executable under `out/pyenv` (available after building Anki). From 510a3b3533d239a56112d6ca62245931bd555073 Mon Sep 17 00:00:00 2001 From: Abdo Date: Mon, 27 Oct 2025 15:31:59 +0300 Subject: [PATCH 07/12] Update VS Code config (#4397) --- .vscode.dist/tasks.json | 3 +-- tools/run.py | 2 -- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/.vscode.dist/tasks.json b/.vscode.dist/tasks.json index 72eab9604..b89704d2e 100644 --- a/.vscode.dist/tasks.json +++ b/.vscode.dist/tasks.json @@ -12,8 +12,7 @@ "command": "tools/ninja.bat", "args": [ "pylib", - "qt", - "extract:win_amd64_audio" + "qt" ] } } diff --git a/tools/run.py b/tools/run.py index da0baa2c4..e17e22a97 100644 --- a/tools/run.py +++ b/tools/run.py @@ -5,8 +5,6 @@ import os import sys sys.path.extend(["pylib", "qt", "out/pylib", "out/qt"]) -if sys.platform == "win32": - os.environ["PATH"] += ";out\\extracted\\win_amd64_audio" import aqt From 23d0657a01de1257091f97b0e18ecc88af55f7fe Mon Sep 17 00:00:00 2001 From: jcznk <60730312+jcznk@users.noreply.github.com> Date: Mon, 27 Oct 2025 13:35:07 +0100 Subject: [PATCH 08/12] (UI polish) Filtered decks: replace maximumSize with sizePolicy in "Limit to" QSpinBox (#4398) * Fix (UI) / Increase width of "Limit to" QSpinBox (Filtered Decks) Increased the width from 60 px to 75 px, so that there is always enough space, even in the case of large numbers (e.g., 99999). * Update filtered_deck.ui (replace maximumSize with sizePolicy) --- qt/aqt/forms/filtered_deck.ui | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/qt/aqt/forms/filtered_deck.ui b/qt/aqt/forms/filtered_deck.ui index 0a90c40e5..a64a3968a 100644 --- a/qt/aqt/forms/filtered_deck.ui +++ b/qt/aqt/forms/filtered_deck.ui @@ -85,11 +85,11 @@ - - - 60 - 16777215 - + + + 0 + 0 + 1 @@ -168,11 +168,11 @@ - - - 60 - 16777215 - + + + 0 + 0 + 1 From 9eb6ec4db8b0f91938498a71ccf2935efc299b33 Mon Sep 17 00:00:00 2001 From: Eltaurus Date: Mon, 27 Oct 2025 18:41:40 +0600 Subject: [PATCH 09/12] Fix unescaped HTML in correct type-in answers (#4407) * Fix unescaped HTML in correct type-in answers * unit test for correct answer escaping * fix string conversion --- CONTRIBUTORS | 1 + rslib/src/typeanswer.rs | 11 ++++++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 43f7a7e46..01573b419 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -252,6 +252,7 @@ Amanda Sternberg arold0 nav1s Ranjit Odedra +Eltaurus ******************** diff --git a/rslib/src/typeanswer.rs b/rslib/src/typeanswer.rs index 08c638e12..9bf3dc47c 100644 --- a/rslib/src/typeanswer.rs +++ b/rslib/src/typeanswer.rs @@ -58,7 +58,7 @@ trait DiffTrait { if self.get_typed() == self.get_expected() { format_typeans!(format!( "{}", - self.get_expected_original() + htmlescape::encode_minimal(&self.get_expected_original()) )) } else { let output = self.to_tokens(); @@ -391,6 +391,15 @@ mod test { assert_eq!(ctx, "123"); } + #[test] + fn correct_input_is_escaped() { + let ctx = Diff::new("source /bin/activate", "source /bin/activate"); + assert_eq!( + ctx.to_html(), + "source <dir>/bin/activate" + ); + } + #[test] fn correct_input_is_collapsed() { let ctx = Diff::new("123", "123"); From 739e41ce16cceffad9ce25e1bbcfe34b70ebbe91 Mon Sep 17 00:00:00 2001 From: llama Date: Mon, 27 Oct 2025 20:42:45 +0800 Subject: [PATCH 10/12] fix(launcher): apply cache settings to all uv invocations (#4404) --- qt/launcher/src/main.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/qt/launcher/src/main.rs b/qt/launcher/src/main.rs index a399a3460..dab9435ea 100644 --- a/qt/launcher/src/main.rs +++ b/qt/launcher/src/main.rs @@ -327,7 +327,6 @@ fn handle_version_install_or_update(state: &State, choice: MainMenuChoice) -> Re } command - .env("UV_CACHE_DIR", &state.uv_cache_dir) .env("UV_PYTHON_INSTALL_DIR", &state.uv_python_install_dir) .env( "UV_HTTP_TIMEOUT", @@ -346,10 +345,6 @@ fn handle_version_install_or_update(state: &State, choice: MainMenuChoice) -> Re } } - if state.no_cache_marker.exists() { - command.env("UV_NO_CACHE", "1"); - } - match command.ensure_success() { Ok(_) => { // Sync succeeded @@ -1024,6 +1019,12 @@ fn uv_command(state: &State) -> Result { .env("UV_DEFAULT_INDEX", &pypi_mirror); } + if state.no_cache_marker.exists() { + command.env("UV_NO_CACHE", "1"); + } else { + command.env("UV_CACHE_DIR", &state.uv_cache_dir); + } + // have uv use the system certstore instead of webpki-roots' command.env("UV_NATIVE_TLS", "1"); From da5b8cb5b41b22bcf87094f55d5b6bd8aed6c708 Mon Sep 17 00:00:00 2001 From: jariji <96840304+jariji@users.noreply.github.com> Date: Tue, 28 Oct 2025 22:51:55 -0700 Subject: [PATCH 11/12] Show text on occlusion cards regardless of occludeInactive (#4387) * Show text on occlusion cards regardless of `occludeInactive`. Before this change, on an image occlusion card, a text box was visible during editing but not visible during review. This change makes text visible even if other shapes would be hidden. * Move fix to render_image_occlusion() --------- Co-authored-by: jariji Co-authored-by: Abdo --- CONTRIBUTORS | 3 ++- rslib/src/cloze.rs | 4 +--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 01573b419..d90b7dbcc 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -189,7 +189,7 @@ Christian Donat Asuka Minato Dillon Baldwin Voczi -Ben Nguyen <105088397+bpnguyen107@users.noreply.github.com> +Ben Nguyen <105088397+bpnguyen107@users.noreply.github.com> Themis Demetriades Luke Bartholomew Gregory Abrasaldo @@ -253,6 +253,7 @@ arold0 nav1s Ranjit Odedra Eltaurus +jariji ******************** diff --git a/rslib/src/cloze.rs b/rslib/src/cloze.rs index 9df53286d..70a5d1703 100644 --- a/rslib/src/cloze.rs +++ b/rslib/src/cloze.rs @@ -260,7 +260,6 @@ fn reveal_cloze( image_occlusion_text, question, active, - cloze_ord, &cloze.ordinals, )); return; @@ -332,10 +331,9 @@ fn render_image_occlusion( text: &str, question_side: bool, active: bool, - ordinal: u16, ordinals: &[u16], ) -> String { - if (question_side && active) || ordinal == 0 { + if (question_side && active) || ordinals.contains(&0) { format!( r#"
"#, ordinals_str(ordinals), From dac26ce67147b261d79a56092320cc2f5af0d990 Mon Sep 17 00:00:00 2001 From: Luc Mcgrady Date: Wed, 29 Oct 2025 17:15:56 +0000 Subject: [PATCH 12/12] Fix/Exclude BackendFrontendService from write_python_interface (#4410) * Fix/Missing python import in write_header * Revert "Fix/Missing python import in write_header" This reverts commit 7c736d984d474377c4326f0cdf473f0e039857c7. * exclude BackendFrontendService --------- Co-authored-by: Abdo --- rslib/proto/python.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rslib/proto/python.rs b/rslib/proto/python.rs index a5adb4179..5c245de1d 100644 --- a/rslib/proto/python.rs +++ b/rslib/proto/python.rs @@ -22,7 +22,7 @@ pub(crate) fn write_python_interface(services: &[BackendService]) -> Result<()> write_header(&mut out)?; for service in services { - if service.name == "BackendAnkidroidService" { + if ["BackendAnkidroidService", "BackendFrontendService"].contains(&service.name.as_str()) { continue; } for method in service.all_methods() {