Merge branch 'main' into main

This commit is contained in:
medProgAyat 2025-11-01 22:13:30 +03:30 committed by GitHub
commit c7bcde589e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
13 changed files with 93 additions and 36 deletions

13
.idea.dist/repo.iml Normal file
View file

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="PYTHON_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/out/pylib" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/pylib" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/qt" isTestSource="false" />
<excludeFolder url="file://$MODULE_DIR$/extra" />
<excludeFolder url="file://$MODULE_DIR$/out/pyenv" />
</content>
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

View file

@ -12,8 +12,7 @@
"command": "tools/ninja.bat", "command": "tools/ninja.bat",
"args": [ "args": [
"pylib", "pylib",
"qt", "qt"
"extract:win_amd64_audio"
] ]
} }
} }

View file

@ -252,6 +252,9 @@ Amanda Sternberg <mandis.sternberg@gmail.com>
arold0 <arold0@icloud.com> arold0 <arold0@icloud.com>
nav1s <nav1s@proton.me> nav1s <nav1s@proton.me>
medProgAyat <hosseinmehriyari1383@gmail.com> medProgAyat <hosseinmehriyari1383@gmail.com>
Ranjit Odedra <ranjitodedra.dev@gmail.com>
Eltaurus <https://github.com/Eltaurus-Lt>
jariji
******************** ********************

View file

@ -46,10 +46,14 @@ see and install a number of recommended extensions.
## PyCharm/IntelliJ ## PyCharm/IntelliJ
If you decide to use PyCharm instead of VS Code, there are somethings to be ### Setting up Python environment
aware of.
### 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).

View file

@ -85,11 +85,11 @@
</item> </item>
<item row="2" column="2"> <item row="2" column="2">
<widget class="QSpinBox" name="limit"> <widget class="QSpinBox" name="limit">
<property name="maximumSize"> <property name="sizePolicy">
<size> <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<width>60</width> <horstretch>0</horstretch>
<height>16777215</height> <verstretch>0</verstretch>
</size> </sizepolicy>
</property> </property>
<property name="minimum"> <property name="minimum">
<number>1</number> <number>1</number>
@ -168,11 +168,11 @@
</item> </item>
<item row="1" column="1"> <item row="1" column="1">
<widget class="QSpinBox" name="limit_2"> <widget class="QSpinBox" name="limit_2">
<property name="maximumSize"> <property name="sizePolicy">
<size> <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<width>60</width> <horstretch>0</horstretch>
<height>16777215</height> <verstretch>0</verstretch>
</size> </sizepolicy>
</property> </property>
<property name="minimum"> <property name="minimum">
<number>1</number> <number>1</number>

View file

@ -260,6 +260,7 @@ class Preferences(QDialog):
self.update_login_status() self.update_login_status()
self.confirm_sync_after_login() self.confirm_sync_after_login()
self.update_network()
sync_login(self.mw, on_success) sync_login(self.mw, on_success)
def sync_logout(self) -> None: def sync_logout(self) -> None:

View file

@ -7,4 +7,7 @@ fn main() {
.manifest_required() .manifest_required()
.unwrap(); .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}");
} }

View file

@ -152,7 +152,9 @@ fn run() -> Result<()> {
let sync_time = file_timestamp_secs(&state.sync_complete_marker); let sync_time = file_timestamp_secs(&state.sync_complete_marker);
state.pyproject_modified_by_user = pyproject_time > sync_time; state.pyproject_modified_by_user = pyproject_time > sync_time;
let pyproject_has_changed = state.pyproject_modified_by_user; 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 // If no launcher request and venv is already up to date, launch Anki normally
let args: Vec<String> = std::env::args().skip(1).collect(); let args: Vec<String> = std::env::args().skip(1).collect();
let cmd = build_python_command(&state, &args)?; let cmd = build_python_command(&state, &args)?;
@ -325,7 +327,6 @@ fn handle_version_install_or_update(state: &State, choice: MainMenuChoice) -> Re
} }
command command
.env("UV_CACHE_DIR", &state.uv_cache_dir)
.env("UV_PYTHON_INSTALL_DIR", &state.uv_python_install_dir) .env("UV_PYTHON_INSTALL_DIR", &state.uv_python_install_dir)
.env( .env(
"UV_HTTP_TIMEOUT", "UV_HTTP_TIMEOUT",
@ -344,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() { match command.ensure_success() {
Ok(_) => { Ok(_) => {
// Sync succeeded // Sync succeeded
@ -603,18 +600,27 @@ fn get_version_kind(state: &State) -> Result<Option<VersionKind>> {
} }
fn with_only_latest_patch(versions: &[String]) -> Vec<String> { fn with_only_latest_patch(versions: &[String]) -> Vec<String> {
// 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(); let mut seen_major_minor = std::collections::HashSet::new();
versions versions
.iter() .iter()
.filter(|v| { .filter(|v| {
let (major, minor, _, _) = parse_version_for_filtering(v); let (major, minor, _, is_prerelease) = parse_version_for_filtering(v);
if major == 2 { if major == 2 {
return true; return true;
} }
let major_minor = (major, minor); let major_minor = (major, minor);
if seen_major_minor.contains(&major_minor) { if seen_major_minor.contains(&major_minor) {
false 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 { } else {
seen_major_minor.insert(major_minor); seen_major_minor.insert(major_minor);
true true
@ -1013,6 +1019,15 @@ fn uv_command(state: &State) -> Result<Command> {
.env("UV_DEFAULT_INDEX", &pypi_mirror); .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");
Ok(command) Ok(command)
} }
@ -1107,6 +1122,20 @@ fn show_mirror_submenu(state: &State) -> Result<()> {
Ok(()) Ok(())
} }
fn diff_launcher_was_installed(state: &State) -> Result<bool> {
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)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;

View file

@ -22,7 +22,7 @@ pub(crate) fn write_python_interface(services: &[BackendService]) -> Result<()>
write_header(&mut out)?; write_header(&mut out)?;
for service in services { for service in services {
if service.name == "BackendAnkidroidService" { if ["BackendAnkidroidService", "BackendFrontendService"].contains(&service.name.as_str()) {
continue; continue;
} }
for method in service.all_methods() { for method in service.all_methods() {

View file

@ -260,7 +260,6 @@ fn reveal_cloze(
image_occlusion_text, image_occlusion_text,
question, question,
active, active,
cloze_ord,
&cloze.ordinals, &cloze.ordinals,
)); ));
return; return;
@ -332,10 +331,9 @@ fn render_image_occlusion(
text: &str, text: &str,
question_side: bool, question_side: bool,
active: bool, active: bool,
ordinal: u16,
ordinals: &[u16], ordinals: &[u16],
) -> String { ) -> String {
if (question_side && active) || ordinal == 0 { if (question_side && active) || ordinals.contains(&0) {
format!( format!(
r#"<div class="cloze" data-ordinal="{}" {}></div>"#, r#"<div class="cloze" data-ordinal="{}" {}></div>"#,
ordinals_str(ordinals), ordinals_str(ordinals),

View file

@ -58,7 +58,7 @@ trait DiffTrait {
if self.get_typed() == self.get_expected() { if self.get_typed() == self.get_expected() {
format_typeans!(format!( format_typeans!(format!(
"<span class=typeGood>{}</span>", "<span class=typeGood>{}</span>",
self.get_expected_original() htmlescape::encode_minimal(&self.get_expected_original())
)) ))
} else { } else {
let output = self.to_tokens(); let output = self.to_tokens();
@ -391,6 +391,15 @@ mod test {
assert_eq!(ctx, "<code id=typeans>123</code>"); assert_eq!(ctx, "<code id=typeans>123</code>");
} }
#[test]
fn correct_input_is_escaped() {
let ctx = Diff::new("source <dir>/bin/activate", "source <dir>/bin/activate");
assert_eq!(
ctx.to_html(),
"<code id=typeans><span class=typeGood>source &lt;dir&gt;/bin/activate</span></code>"
);
}
#[test] #[test]
fn correct_input_is_collapsed() { fn correct_input_is_collapsed() {
let ctx = Diff::new("123", "123"); let ctx = Diff::new("123", "123");

View file

@ -5,8 +5,6 @@ import os
import sys import sys
sys.path.extend(["pylib", "qt", "out/pylib", "out/qt"]) sys.path.extend(["pylib", "qt", "out/pylib", "out/qt"])
if sys.platform == "win32":
os.environ["PATH"] += ";out\\extracted\\win_amd64_audio"
import aqt import aqt

View file

@ -6939,8 +6939,8 @@ __metadata:
linkType: hard linkType: hard
"vite@npm:6": "vite@npm:6":
version: 6.3.6 version: 6.4.1
resolution: "vite@npm:6.3.6" resolution: "vite@npm:6.4.1"
dependencies: dependencies:
esbuild: "npm:^0.25.0" esbuild: "npm:^0.25.0"
fdir: "npm:^6.4.4" fdir: "npm:^6.4.4"
@ -6989,7 +6989,7 @@ __metadata:
optional: true optional: true
bin: bin:
vite: bin/vite.js vite: bin/vite.js
checksum: 10c0/add701f1e72596c002275782e38d0389ab400c1be330c93a3009804d62db68097a936ca1c53c3301df3aaacfe5e328eab547060f31ef9c49a277ae50df6ad4fb checksum: 10c0/77bb4c5b10f2a185e7859cc9a81c789021bc18009b02900347d1583b453b58e4b19ff07a5e5a5b522b68fc88728460bb45a63b104d969e8c6a6152aea3b849f7
languageName: node languageName: node
linkType: hard linkType: hard