feat: support font arguments

This commit is contained in:
Myriad-Dreamin 2024-03-11 02:24:27 +08:00
parent 0be0fe07c2
commit 1c825607b2
12 changed files with 2623 additions and 33 deletions

4
Cargo.lock generated
View file

@ -3589,7 +3589,7 @@ dependencies = [
[[package]]
name = "tinymist"
version = "0.11.0"
version = "0.10.0"
dependencies = [
"anyhow",
"async-trait",
@ -3627,7 +3627,7 @@ dependencies = [
[[package]]
name = "tinymist-query"
version = "0.11.0"
version = "0.10.0"
dependencies = [
"anyhow",
"comemo 0.4.0",

View file

@ -1,7 +1,7 @@
[workspace.package]
description = "An integrated language service for Typst."
authors = ["Myriad-Dreamin <camiyoru@gmail.com>", "Nathan Varner"]
version = "0.11.0"
version = "0.10.0"
edition = "2021"
readme = "README.md"
license = "Apache-2.0"

View file

@ -41,10 +41,9 @@ impl TypstLanguageServer {
let opts = CompileOpts {
root_dir,
// todo: font paths
// font_paths: arguments.font_paths.clone(),
// todo: additional inputs
with_embedded_fonts: typst_assets::fonts().map(Cow::Borrowed).collect(),
..CompileOpts::default()
..self.compile_opts.clone()
};
create_server(
name,

View file

@ -1,5 +1,10 @@
use std::path::PathBuf;
use once_cell::sync::Lazy;
#[cfg(feature = "clap")]
const ENV_PATH_SEP: char = if cfg!(windows) { ';' } else { ':' };
#[derive(Debug, Clone)]
#[cfg_attr(feature = "clap", derive(clap::Parser))]
#[cfg_attr(feature = "clap", clap(name = "tinymist", author, version, about, long_version(LONG_VERSION.as_str())))]
@ -16,6 +21,18 @@ pub struct CliArguments {
/// Replay input from the file
#[cfg_attr(feature = "clap", clap(long, default_value = "", value_name = "FILE"))]
pub replay: String,
/// Font paths, which doesn't allow for dynamic configuration
#[cfg_attr(feature = "clap", clap(
long = "font-path",
value_name = "DIR",
action = clap::ArgAction::Append,
env = "TYPST_FONT_PATHS",
value_delimiter = ENV_PATH_SEP
))]
pub font_paths: Vec<PathBuf>,
/// Exclude system fonts
#[cfg_attr(feature = "clap", clap(long, default_value = "false"))]
pub no_system_fonts: bool,
}
pub static LONG_VERSION: Lazy<String> = Lazy::new(|| {

View file

@ -9,9 +9,10 @@ use serde::Deserialize;
use serde_json::{Map, Value as JsonValue};
use tinymist_query::{get_semantic_tokens_options, PositionEncoding};
use tokio::sync::mpsc;
use typst_ts_core::config::CompileOpts;
use crate::actor::cluster::CompileClusterActor;
use crate::{invalid_params, LspHost, LspResult, TypstLanguageServer};
use crate::{invalid_params, LspHost, LspResult, TypstLanguageServer, TypstLanguageServerArgs};
trait InitializeParamsExt {
fn position_encodings(&self) -> &[PositionEncodingKind];
@ -335,6 +336,7 @@ impl From<&InitializeParams> for ConstConfig {
pub struct Init {
pub host: LspHost,
pub compile_opts: CompileOpts,
}
impl Init {
@ -371,8 +373,13 @@ impl Init {
// Bootstrap server
let (diag_tx, diag_rx) = mpsc::unbounded_channel();
let mut service =
TypstLanguageServer::new(self.host.clone(), params.root_paths(), cc, diag_tx);
let mut service = TypstLanguageServer::new(TypstLanguageServerArgs {
client: self.host.clone(),
compile_opts: self.compile_opts,
roots: params.root_paths(),
const_config: cc,
diag_tx,
});
if let Some(init) = &params.initialization_options {
if let Err(err) = config

View file

@ -59,6 +59,7 @@ use tinymist_query::{
};
use tokio::sync::mpsc;
use typst::util::Deferred;
use typst_ts_core::config::CompileOpts;
pub type MaySyncResult<'a> = Result<JsonValue, BoxFuture<'a, JsonValue>>;
@ -256,6 +257,14 @@ fn as_path_pos(inp: TextDocumentPositionParams) -> (PathBuf, Position) {
(as_path(inp.text_document), inp.position)
}
pub struct TypstLanguageServerArgs {
pub client: LspHost,
pub compile_opts: CompileOpts,
pub roots: Vec<PathBuf>,
pub const_config: ConstConfig,
pub diag_tx: mpsc::UnboundedSender<(String, Option<DiagnosticsMap>)>,
}
/// The object providing the language server functionality.
pub struct TypstLanguageServer {
/// The language server client.
@ -273,6 +282,8 @@ pub struct TypstLanguageServer {
/// Const configuration initialized at the start of the session.
/// For example, the position encoding.
pub const_config: ConstConfig,
/// The default opts for the compiler.
pub compile_opts: CompileOpts,
diag_tx: mpsc::UnboundedSender<(String, Option<DiagnosticsMap>)>,
roots: Vec<PathBuf>,
@ -285,23 +296,19 @@ pub struct TypstLanguageServer {
/// Getters and the main loop.
impl TypstLanguageServer {
/// Create a new language server.
pub fn new(
client: LspHost,
roots: Vec<PathBuf>,
const_config: ConstConfig,
diag_tx: mpsc::UnboundedSender<(String, Option<DiagnosticsMap>)>,
) -> Self {
pub fn new(args: TypstLanguageServerArgs) -> Self {
Self {
client: client.clone(),
client: args.client.clone(),
shutdown_requested: false,
config: Default::default(),
const_config,
const_config: args.const_config,
compile_opts: args.compile_opts,
exec_cmds: Self::get_exec_commands(),
regular_cmds: Self::get_regular_cmds(),
notify_cmds: Self::get_notify_cmds(),
diag_tx,
roots,
diag_tx: args.diag_tx,
roots: args.roots,
memory_changes: RwLock::new(HashMap::new()),
primary: OnceCell::new(),
main: Arc::new(Mutex::new(None)),

View file

@ -9,6 +9,7 @@ use log::{info, trace, warn};
use lsp_types::{InitializeParams, InitializedParams};
use serde::de::DeserializeOwned;
use tinymist::{init::Init, transport::io_transport, LspHost};
use typst_ts_core::config::CompileOpts;
use crate::args::CliArguments;
@ -111,8 +112,15 @@ async fn main() -> anyhow::Result<()> {
let initialize_params = from_json::<InitializeParams>("InitializeParams", &initialize_params)?;
let (mut service, initialize_result) =
Init { host: host.clone() }.initialize(initialize_params.clone());
let (mut service, initialize_result) = Init {
host: host.clone(),
compile_opts: CompileOpts {
font_paths: args.font_paths,
no_system_fonts: args.no_system_fonts,
..Default::default()
},
}
.initialize(initialize_params.clone());
host.respond(match initialize_result {
Ok(cap) => Response::new_ok(initialize_id, Some(cap)),
@ -159,16 +167,6 @@ async fn main() -> anyhow::Result<()> {
service.initialized(InitializedParams {});
// // Set up LSP server
// let (inner, socket) = LspService::new();
// let service = LogService {
// inner,
// show_time: true,
// };
// // Handle requests
// Server::new(stdin, stdout, socket).serve(service).await;
service.main_loop(connection.receiver)?;
io_threads.join()?;

View file

@ -1 +1,2 @@
tinymist-*.vsix
*.log

View file

@ -13,7 +13,7 @@
],
"publisher": "myriad-dreamin",
"license": "Apache-2.0",
"version": "0.11.0",
"version": "0.10.0",
"engines": {
"vscode": "^1.71.0"
},
@ -72,6 +72,24 @@
"Do not use semantic tokens for syntax highlighting"
]
},
"tinymist.noSystemFonts": {
"title": "whether to load system fonts for Typst compiler",
"description": "A flag that determines whether to load system fonts for Typst compiler, which is useful for ensuring reproducible compilation. If set to null or not set, the extension will use the default behavior of the Typst compiler.",
"type": [
"boolean",
"null"
],
"default": null
},
"tinymist.fontPaths": {
"title": "Font paths for Typst compiler",
"description": "Font paths, which doesn't allow for dynamic configuration",
"type": [
"array",
"null"
],
"default": null
},
"tinymist.serverPath": {
"title": "Path to server executable",
"description": "The extension can use a local tinymist executable instead of the one bundled with the extension. This setting controls the path to the executable.",
@ -338,7 +356,8 @@
"test": ""
},
"dependencies": {
"vscode-languageclient": "^9.0.1"
"vscode-languageclient": "^9.0.1",
"vscode-variables": "^0.1.3"
},
"devDependencies": {
"@types/node": "^20.8.10",

View file

@ -9,6 +9,7 @@ import {
TextEditor,
ExtensionMode,
} from "vscode";
import * as vscode from "vscode";
import * as path from "path";
import * as child_process from "child_process";
@ -17,6 +18,7 @@ import {
type LanguageClientOptions,
type ServerOptions,
} from "vscode-languageclient/node";
import vscodeVariables from "vscode-variables";
let client: LanguageClient | undefined = undefined;
@ -30,6 +32,9 @@ export function activate(context: ExtensionContext): Promise<void> {
async function startClient(context: ExtensionContext): Promise<void> {
const config = workspace.getConfiguration("tinymist");
const serverCommand = getServer(config);
const fontPaths = vscode.workspace.getConfiguration().get<string[]>("tinymist.fontPaths");
const noSystemFonts =
vscode.workspace.getConfiguration().get<boolean | null>("tinymist.noSystemFonts") === true;
const run = {
command: serverCommand,
args: [
@ -38,6 +43,8 @@ async function startClient(context: ExtensionContext): Promise<void> {
...(context.extensionMode != ExtensionMode.Production
? ["--mirror", "tinymist-lsp.log"]
: []),
...(fontPaths ?? []).flatMap((fontPath) => ["--font-path", vscodeVariables(fontPath)]),
...(noSystemFonts ? ["--no-system-fonts"] : []),
],
options: { env: Object.assign({}, process.env, { RUST_BACKTRACE: "1" }) },
};
@ -166,6 +173,7 @@ async function commandShowPdf(): Promise<void> {
return;
}
// todo: this is wrong
const uri = activeEditor.document.uri;
// change the file extension to `.pdf` as we want to open the pdf file
// and not the currently opened `.typ` file.

View file

@ -0,0 +1,3 @@
declare module "vscode-variables" {
export default function vscodeVariables<T>(arg: T): T;
}

2531
editors/vscode/yarn.lock Normal file

File diff suppressed because it is too large Load diff