mitex_spec/
query.rs

1//! The query module contains the data structures that are used by `typst query
2//! <mitex-packages>`
3
4use std::{collections::HashMap, sync::Arc};
5
6use serde::{Deserialize, Serialize};
7
8use crate::{CmdShape, ContextFeature, EnvShape};
9
10/// A package specification.
11#[derive(Debug, Clone, Serialize, Deserialize)]
12pub struct PackageSpec {
13    /// The name of the package.
14    pub name: String,
15    /// The command specification of the package.
16    pub spec: CommandSpecRepr,
17}
18
19/// A ordered list of package specifications.
20///
21/// The latter package specification will override the former one.
22#[derive(Debug, Clone, Serialize, Deserialize)]
23pub struct PackagesVec(pub Vec<PackageSpec>);
24
25/// An item of command specification.
26/// This enum contains more sugar than the canonical representation.
27///
28/// See [`crate::CommandSpecItem`] for more details.
29#[derive(Debug, Clone, Serialize, Deserialize)]
30#[serde(tag = "kind")]
31pub enum CommandSpecItem {
32    /// A canonical command item.
33    #[serde(rename = "cmd")]
34    Cmd(CmdShape),
35    /// A canonical environment item.
36    #[serde(rename = "env")]
37    Env(EnvShape),
38    /// A command that takes no argument, and its handler is also a typst
39    /// symbol.
40    #[serde(rename = "sym")]
41    Symbol,
42    /// A command that takes zero argument, and its handler is a typst function.
43    #[serde(rename = "cmd0")]
44    Command0,
45    /// A command that takes one argument.
46    #[serde(rename = "cmd1")]
47    Command1,
48    /// A command that takes two arguments.
49    #[serde(rename = "cmd2")]
50    Command2,
51    /// A command that takes one argument and is a left-associative operator.
52    #[serde(rename = "left1-cmd")]
53    CmdLeft1,
54    /// A command that takes no argument and is a matrix environment.
55    #[serde(rename = "matrix-env")]
56    EnvMatrix,
57    /// A command that takes no argument and is a normal environment.
58    #[serde(rename = "normal-env")]
59    EnvNormal,
60    /// A command that has a glob argument pattern and is an environment.
61    #[serde(rename = "glob-env")]
62    EnvGlob {
63        /// The glob pattern of the command.
64        pattern: String,
65        /// The aliasing typst handle of the command.
66        alias: String,
67        /// The context feature of the command.
68        ctx_feature: ContextFeature,
69    },
70
71    /// A command that is aliased to a Typst symbol.
72    #[serde(rename = "alias-sym")]
73    SymAlias {
74        /// The aliasing typst handle of the symbol.
75        alias: String,
76    },
77    /// A command that is greedy and is aliased to a Typst handler.
78    #[serde(rename = "greedy-cmd")]
79    CmdGreedy {
80        /// The aliasing typst handle of the command.
81        alias: String,
82    },
83    /// A command that is an infix operator and is aliased to a Typst handler.
84    #[serde(rename = "infix-cmd")]
85    CmdInfix {
86        /// The aliasing typst handle of the command.
87        alias: String,
88    },
89    /// A command that has a glob argument pattern and is aliased to a Typst
90    /// handler.
91    #[serde(rename = "glob-cmd")]
92    CmdGlob {
93        /// The glob pattern of the command.
94        pattern: String,
95        /// The aliasing typst handle of the command.
96        alias: String,
97    },
98}
99
100impl From<CommandSpecItem> for crate::CommandSpecItem {
101    fn from(item: CommandSpecItem) -> Self {
102        use crate::preludes::command::*;
103        match item {
104            CommandSpecItem::Cmd(shape) => Self::Cmd(shape),
105            CommandSpecItem::Env(shape) => Self::Env(shape),
106            CommandSpecItem::Symbol => TEX_SYMBOL,
107            CommandSpecItem::Command0 => TEX_CMD0,
108            CommandSpecItem::Command1 => TEX_CMD1,
109            CommandSpecItem::Command2 => TEX_CMD2,
110            CommandSpecItem::CmdLeft1 => TEX_LEFT1_OPEARTOR,
111            CommandSpecItem::EnvMatrix => TEX_MATRIX_ENV,
112            CommandSpecItem::EnvNormal => TEX_NORMAL_ENV,
113            CommandSpecItem::EnvGlob {
114                pattern,
115                alias,
116                ctx_feature,
117            } => define_glob_env(&pattern, &alias, ctx_feature),
118            CommandSpecItem::SymAlias { alias } => define_symbol(&alias),
119            CommandSpecItem::CmdGreedy { alias } => define_greedy_command(&alias),
120            CommandSpecItem::CmdInfix { alias } => crate::CommandSpecItem::Cmd(crate::CmdShape {
121                args: crate::ArgShape::InfixGreedy,
122                alias: Some(alias.to_owned()),
123            }),
124            CommandSpecItem::CmdGlob { pattern, alias } => define_glob_command(&pattern, &alias),
125        }
126    }
127}
128
129/// Command specification that contains a set of commands and environments. It
130/// is used for us to define the meta data of LaTeX packages in typst code and
131/// query by `typst query` then. See [`Spec`] for an example.
132///
133/// Note: There are non-canonical format of items could be used for convenience.
134///
135/// [`Spec`]: https://github.com/mitex-rs/mitex/tree/main/packages/mitex/specs
136#[derive(Default, Debug, Clone, Serialize, Deserialize)]
137pub struct CommandSpecRepr {
138    /// The command specifications.
139    pub commands: HashMap<String, CommandSpecItem>,
140}
141
142impl From<CommandSpecRepr> for crate::CommandSpec {
143    fn from(repr: CommandSpecRepr) -> Self {
144        Self(Arc::new(repr.into()))
145    }
146}
147
148impl From<CommandSpecRepr> for crate::CommandSpecRepr {
149    fn from(repr: CommandSpecRepr) -> Self {
150        Self {
151            commands: repr
152                .commands
153                .into_iter()
154                .map(|(k, v)| (k, v.into()))
155                .collect(),
156        }
157    }
158}