dev: collect server information for summary (#162)

* dev: collect server information for summary

* dev: humanize font variant to show

* fix: let focus state correct
This commit is contained in:
Myriad-Dreamin 2024-04-05 13:18:36 +08:00 committed by GitHub
parent 6722b2501f
commit 703c8b4c1d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
13 changed files with 467 additions and 46 deletions

View file

@ -15,8 +15,7 @@ use typst::syntax::Source;
use super::SearchCtx;
use crate::syntax::{
find_source_by_import_path, get_lexical_hierarchy, IdentRef, LexicalHierarchy, LexicalKind,
LexicalScopeKind, LexicalVarKind, ModSrc,
find_source_by_import_path, IdentRef, LexicalHierarchy, LexicalKind, LexicalVarKind, ModSrc,
};
use crate::{adt::snapshot_map::SnapshotMap, syntax::LexicalModKind};
@ -57,6 +56,23 @@ pub struct DefUseInfo {
}
impl DefUseInfo {
/// Get the estimated memory usage of the def-use information.
pub fn estimated_memory(&self) -> usize {
std::mem::size_of::<Self>()
+ self.ident_defs.capacity()
* (std::mem::size_of::<IdentDef>() + std::mem::size_of::<IdentRef>() + 32)
+ self.external_refs.capacity()
* (std::mem::size_of::<(TypstFileId, Option<String>)>()
+ std::mem::size_of::<Vec<(Option<DefId>, IdentRef)>>()
+ 32)
+ self.ident_refs.capacity()
* (std::mem::size_of::<IdentRef>() + std::mem::size_of::<DefId>() + 32)
+ (self.undefined_refs.capacity() * std::mem::size_of::<IdentRef>() + 32)
+ (self.exports_refs.capacity() * std::mem::size_of::<DefId>() + 32)
+ self.exports_defs.capacity()
* (std::mem::size_of::<String>() + std::mem::size_of::<DefId>() + 32)
}
/// Get the definition id of a symbol by its name reference.
pub fn get_ref(&self, ident: &IdentRef) -> Option<DefId> {
self.ident_refs.get(ident).copied()
@ -112,7 +128,7 @@ pub(super) fn get_def_use_inner(ctx: &mut SearchCtx, source: Source) -> Option<A
return None;
}
let e = get_lexical_hierarchy(source, LexicalScopeKind::DefUse)?;
let e = ctx.ctx.def_use_lexical_hierarchy(source)?;
let mut collector = DefUseCollector {
ctx,

View file

@ -1,9 +1,11 @@
use std::{
collections::{HashMap, HashSet},
hash::Hash,
path::{Path, PathBuf},
sync::Arc,
};
use ecow::EcoVec;
use once_cell::sync::OnceCell;
use reflexo::{cow_mut::CowMut, debug_loc::DataSource, ImmutPath};
use typst::syntax::FileId as TypstFileId;
@ -17,7 +19,9 @@ use typst::{
use super::{get_def_use_inner, DefUseInfo};
use crate::{
lsp_to_typst,
syntax::{construct_module_dependencies, scan_workspace_files, ModuleDependency},
syntax::{
construct_module_dependencies, scan_workspace_files, LexicalHierarchy, ModuleDependency,
},
typst_to_lsp, LspPosition, LspRange, PositionEncoding, TypstRange,
};
@ -59,6 +63,102 @@ pub struct Analysis {
pub root: ImmutPath,
/// The position encoding for the workspace.
pub position_encoding: PositionEncoding,
/// The global caches for analysis.
pub caches: AnalysisGlobalCaches,
}
impl Analysis {
/// Get estimated memory usage of the analysis data.
pub fn estimated_memory(&self) -> usize {
self.caches.modules.capacity() * 32
+ self
.caches
.modules
.values()
.map(|v| {
v.def_use_lexical_heirarchy
.output
.as_ref()
.map_or(0, |e| e.iter().map(|e| e.estimated_memory()).sum())
})
.sum::<usize>()
}
}
struct ComputingNode<Inputs, Output> {
name: &'static str,
inputs: Option<Inputs>,
output: Option<Output>,
}
pub(crate) trait ComputeDebug {
fn compute_debug_repr(&self) -> impl std::fmt::Debug;
}
impl ComputeDebug for Source {
fn compute_debug_repr(&self) -> impl std::fmt::Debug {
self.id()
}
}
impl<Inputs, Output> ComputingNode<Inputs, Output> {
fn new(name: &'static str) -> Self {
Self {
name,
inputs: None,
output: None,
}
}
fn compute(
&mut self,
inputs: Inputs,
compute: impl FnOnce(Option<Inputs>, Inputs) -> Option<Output>,
) -> Option<Output>
where
Inputs: ComputeDebug + Hash + Clone,
Output: Clone,
{
match &self.inputs {
Some(s) if reflexo::hash::hash128(&inputs) == reflexo::hash::hash128(&s) => {
log::debug!(
"{}({:?}): hit cache",
self.name,
inputs.compute_debug_repr()
);
self.output.clone()
}
_ => {
log::info!("{}({:?}): compute", self.name, inputs.compute_debug_repr());
let output = compute(self.inputs.clone(), inputs.clone());
self.output = output.clone();
self.inputs = Some(inputs);
output
}
}
}
}
/// A cache for module-level analysis results of a module.
///
/// You should not holds across requests, because source code may change.
pub struct ModuleAnalysisGlobalCache {
def_use_lexical_heirarchy: ComputingNode<Source, EcoVec<LexicalHierarchy>>,
}
impl Default for ModuleAnalysisGlobalCache {
fn default() -> Self {
Self {
def_use_lexical_heirarchy: ComputingNode::new("def_use_lexical_heirarchy"),
}
}
}
/// A global (compiler server spanned) cache for all level of analysis results
/// of a module.
#[derive(Default)]
pub struct AnalysisGlobalCaches {
modules: HashMap<TypstFileId, ModuleAnalysisGlobalCache>,
}
/// A cache for all level of analysis results of a module.
@ -233,6 +333,21 @@ impl<'w> AnalysisContext<'w> {
pub fn to_lsp_range(&self, position: TypstRange, src: &Source) -> LspRange {
typst_to_lsp::range(position, src, self.analysis.position_encoding)
}
pub(crate) fn def_use_lexical_hierarchy(
&mut self,
source: Source,
) -> Option<EcoVec<LexicalHierarchy>> {
self.analysis
.caches
.modules
.entry(source.id())
.or_default()
.def_use_lexical_heirarchy
.compute(source, |_before, after| {
crate::syntax::get_lexical_hierarchy(after, crate::syntax::LexicalScopeKind::DefUse)
})
}
}
/// The context for searching in the workspace.

View file

@ -3,7 +3,7 @@ use std::{collections::HashMap, path::PathBuf};
use reflexo::debug_loc::DataSource;
use serde::{Deserialize, Serialize};
use typst::text::Font;
use typst::text::{Font, FontStretch, FontStyle, FontWeight};
use typst::{
layout::{Frame, FrameItem},
model::Document,
@ -39,6 +39,12 @@ pub struct DocumentFontInfo {
/// The display name of the font, which is computed by this crate and
/// unnecessary from any fields of the font file.
pub name: String,
/// The style of the font.
pub style: FontStyle,
/// The weight of the font.
pub weight: FontWeight,
/// The stretch of the font.
pub stretch: FontStretch,
/// The PostScript name of the font.
pub postscript_name: Option<String>,
/// The Family in font file.
@ -165,12 +171,16 @@ impl<'a, 'w> DocumentMetricsWorker<'a, 'w> {
.into_iter()
.map(|(font, uses)| {
let extra = self.ctx.resources.font_info(font.clone());
let info = &font.info();
DocumentFontInfo {
name: format!("{} ({:?})", font.info().family, font.info().variant),
name: info.family.clone(),
style: info.variant.style,
weight: info.variant.weight,
stretch: info.variant.stretch,
postscript_name: font.find_name(POST_SCRIPT_NAME),
full_name: font.find_name(FULL_NAME),
family: font.find_name(FAMILY),
fixed_family: Some(font.info().family.clone()),
fixed_family: Some(info.family.clone()),
source: extra.map(|e| self.internal_source(e)),
index: Some(font.index()),
uses_scale: Some(uses),

View file

@ -113,6 +113,7 @@ pub trait StatefulRequest {
mod polymorphic {
use lsp_types::TextEdit;
use serde::{Deserialize, Serialize};
use typst::foundations::Dict;
use super::prelude::*;
use super::*;
@ -161,6 +162,19 @@ mod polymorphic {
pub path: PathBuf,
}
#[derive(Debug, Clone)]
pub struct ServerInfoRequest {}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ServerInfoReponse {
pub root: Option<PathBuf>,
#[serde(rename = "fontPaths")]
pub font_paths: Vec<PathBuf>,
pub inputs: Dict,
#[serde(rename = "estimatedMemoryUsage")]
pub estimated_memory_usage: HashMap<String, usize>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum FoldRequestFeature {
PinnedFirst,
@ -192,6 +206,7 @@ mod polymorphic {
SelectionRange(SelectionRangeRequest),
DocumentMetrics(DocumentMetricsRequest),
ServerInfo(ServerInfoRequest),
}
impl CompilerQueryRequest {
@ -219,6 +234,7 @@ mod polymorphic {
CompilerQueryRequest::SelectionRange(..) => ContextFreeUnique,
CompilerQueryRequest::DocumentMetrics(..) => PinnedFirst,
CompilerQueryRequest::ServerInfo(..) => Mergable,
}
}
@ -245,6 +261,7 @@ mod polymorphic {
CompilerQueryRequest::SelectionRange(req) => &req.path,
CompilerQueryRequest::DocumentMetrics(req) => &req.path,
CompilerQueryRequest::ServerInfo(..) => return None,
})
}
}
@ -272,6 +289,7 @@ mod polymorphic {
SelectionRange(Option<Vec<SelectionRange>>),
DocumentMetrics(Option<DocumentMetricsResponse>),
ServerInfo(Option<HashMap<String, ServerInfoReponse>>),
}
}

View file

@ -233,6 +233,18 @@ pub(crate) struct LexicalHierarchy {
pub children: Option<LazyHash<EcoVec<LexicalHierarchy>>>,
}
impl LexicalHierarchy {
pub fn estimated_memory(&self) -> usize {
std::mem::size_of::<Self>()
+ std::mem::size_of::<LexicalInfo>()
+ self.info.name.len()
+ self
.children
.as_ref()
.map_or(0, |c| c.iter().map(|e| e.estimated_memory()).sum())
}
}
impl Serialize for LexicalHierarchy {
fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
use serde::ser::SerializeStruct;

View file

@ -74,6 +74,7 @@ pub fn snapshot_testing(name: &str, f: &impl Fn(&mut AnalysisContext, PathBuf))
Analysis {
root,
position_encoding: PositionEncoding::Utf16,
caches: Default::default(),
},
);
ctx.test_files(|| paths);