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