Merge remote-tracking branch 'upstream/main' into import-package-tooltip

This commit is contained in:
QuadnucYard 2025-12-16 10:33:21 +08:00
commit 2c61f06434
8 changed files with 66 additions and 33 deletions

View file

@ -6,7 +6,7 @@
"lsp": {
"rust-analyzer": {
"initialization_options": {
"checkOnSave": {
"check": {
"command": "clippy"
}
}

View file

@ -30,12 +30,14 @@ impl CompletionPair<'_, '_, '_> {
/// Add completions for all available packages.
pub fn package_completions(&mut self, all_versions: bool) {
let w = self.worker.world().clone();
// Finds packages that are in `@preview`
let mut packages = w.packages().iter().collect_vec();
// local_packages to references and add them to the packages
// Finds packages that are not in `@preview`
#[cfg(feature = "local-registry")]
let local_packages_refs = self.worker.ctx.local_packages();
let other_packages_refs = self.worker.ctx.non_preview_packages();
#[cfg(feature = "local-registry")]
packages.extend(local_packages_refs.iter());
packages.extend(other_packages_refs.iter());
packages.sort_by_key(|entry| {
(

View file

@ -689,10 +689,16 @@ impl SharedContext {
self.world().font_resolver.describe_font(&font)
}
/// Gets the local packages and their descriptions.
pub fn local_packages(&self) -> EcoVec<PackageIndexEntry> {
/// Gets the packages other than that in the preview namespace and their
/// descriptions.
pub fn non_preview_packages(&self) -> EcoVec<PackageIndexEntry> {
#[cfg(feature = "local-registry")]
let it = || crate::package::list_package(self.world(), None);
let it = || {
crate::package::list_package(
self.world(),
crate::package::PackageFilter::ExceptFor(EcoString::inline("preview")),
)
};
#[cfg(not(feature = "local-registry"))]
let it = || Default::default();
self.analysis.local_packages.lock().get_or_init(it).clone()

View file

@ -259,9 +259,9 @@ impl HoverWorker<'_> {
.filter(|it| it.matches_versionless(&versionless_spec)),
);
}
// local_packages to references and add them to the packages
// Add non-preview packages
#[cfg(feature = "local-registry")]
let local_packages = self.ctx.local_packages();
let local_packages = self.ctx.non_preview_packages();
#[cfg(feature = "local-registry")]
if !package_spec.is_preview() {
packages.extend(

View file

@ -77,11 +77,22 @@ pub fn check_package(ctx: &mut LocalContext, spec: &PackageInfo) -> StrResult<()
Ok(())
}
/// A filter for packages.
#[cfg(feature = "local-registry")]
pub enum PackageFilter {
/// Filter for packages that match the given namespace.
For(EcoString),
/// Filter for packages that do not match the given namespace.
ExceptFor(EcoString),
/// Filter that matches all packages.
All,
}
#[cfg(feature = "local-registry")]
/// Get the packages in namespaces and their descriptions.
pub fn list_package(
world: &tinymist_project::LspWorld,
ns: Option<EcoString>,
filter: PackageFilter,
) -> EcoVec<PackageIndexEntry> {
trait IsDirFollowLinks {
fn is_dir_follow_links(&self) -> bool;
@ -104,10 +115,8 @@ pub fn list_package(
// intended for storage of local packages.
let mut packages = eco_vec![];
log::info!(
"searching for packages in namespace {ns:?} in paths {:?}",
registry.paths()
);
let paths = registry.paths();
log::info!("searching for packages in paths {paths:?}");
let mut search_in_dir = |local_path: PathBuf, ns: EcoString| {
if !local_path.exists() || !local_path.is_dir_follow_links() {
@ -179,22 +188,34 @@ pub fn list_package(
}
};
for dir in registry.paths() {
if let Some(ns) = &ns {
let local_path = dir.join(ns.as_str());
search_in_dir(local_path, ns.clone());
} else {
let Some(namespaces) = once_log(std::fs::read_dir(dir), "read package directory")
else {
for dir in paths {
let matching_ns = match &filter {
PackageFilter::For(ns) => {
let local_path = dir.join(ns.as_str());
search_in_dir(local_path, ns.clone());
continue;
}
PackageFilter::ExceptFor(ns) => Some(ns),
PackageFilter::All => None,
};
let Some(namespaces) = once_log(std::fs::read_dir(dir), "read package directory") else {
continue;
};
for dir in namespaces {
let Some(dir) = once_log(dir, "read ns directory") else {
continue;
};
for dir in namespaces {
let Some(dir) = once_log(dir, "read ns directory") else {
continue;
};
let local_path = dir.path();
search_in_dir(local_path, dir.file_name().to_string_lossy().into());
let ns = dir.file_name();
let ns = ns.to_string_lossy();
if let Some(matching_ns) = &matching_ns
&& matching_ns.as_str() == ns.as_ref()
{
continue;
}
let local_path = dir.path();
search_in_dir(local_path, ns.into());
}
}

View file

@ -484,10 +484,13 @@ impl ServerState {
let snap = self.snapshot().map_err(internal_error)?;
just_future(async move {
let packages = tinymist_query::package::list_package(snap.world(), Some(ns))
.into_iter()
.map(PackageInfo::from)
.collect::<Vec<_>>();
let packages = tinymist_query::package::list_package(
snap.world(),
tinymist_query::package::PackageFilter::For(ns),
)
.into_iter()
.map(PackageInfo::from)
.collect::<Vec<_>>();
serde_json::to_value(packages).map_err(|e| internal_error(e.to_string()))
})

View file

@ -63,6 +63,7 @@ ${cjkChars} CJK ${plural("Character", cjkChars)}
const formatString = statusBarFormatString()
.replace(/\{wordCount\}/g, `${words} ${plural("Word", words)}`)
.replace(/\{charCount\}/g, `${chars} ${plural("Character", chars)}`)
.replace(/\{pageCount\}/g, `${pages} ${plural("Page", pages)}`)
.replace(/\{fileName\}/g, fileNameWithoutExt);

View file

@ -1184,8 +1184,8 @@ en = "Status Bar Format"
zh = "状态栏格式"
[extension.tinymist.config.tinymist.statusBarFormat.desc]
en = "Set format string of the server status. For example, `{compileStatusIcon}{wordCount} [{fileName}]` will format the status as `$(check) 123 words [main]`. Valid placeholders are:\n\n- `{compileStatusIcon}`: Icon indicating the compile status\n- `{wordCount}`: Number of words in the document\n- `{fileName}`: Name of the file being compiled\n\nNote: The status bar will be hidden if the format string is empty."
zh = "设置服务器状态的格式字符串。例如,`{compileStatusIcon}{wordCount} [{fileName}]` 将格式化状态为 `$(check) 123 words [main]`。有效的占位符包括:\n\n- `{compileStatusIcon}`:指示编译状态的图标\n- `{wordCount}`:文档中的字数\n- `{fileName}`:正在编译的文件的名称\n\n注意如果格式字符串为空则状态栏将被隐藏。"
en = "Set format string of the server status. For example, `{compileStatusIcon}{wordCount} [{fileName}]` will format the status as `$(check) 123 words [main]`. Valid placeholders are:\n\n- `{compileStatusIcon}`: Icon indicating the compile status\n- `{wordCount}`: Number of words in the document\n- `{charCount}`: Number of characters in the document\n- `{fileName}`: Name of the file being compiled\n\nNote: The status bar will be hidden if the format string is empty."
zh = "设置服务器状态的格式字符串。例如,`{compileStatusIcon}{wordCount} [{fileName}]` 将格式化状态为 `$(check) 123 words [main]`。有效的占位符包括:\n\n- `{compileStatusIcon}`:指示编译状态的图标\n- `{wordCount}`:文档中的字数\n- `{charCount}`:文档中的字符数\n- `{fileName}`:正在编译的文件的名称\n\n注意如果格式字符串为空则状态栏将被隐藏。"
[extension.tinymist.config.tinymist.typstExtraArgs.title]
en = "Typst Extra Arguments"