summaryrefslogtreecommitdiff
path: root/support/texlab/crates/texlab/src/main.rs
diff options
context:
space:
mode:
Diffstat (limited to 'support/texlab/crates/texlab/src/main.rs')
-rw-r--r--support/texlab/crates/texlab/src/main.rs67
1 files changed, 60 insertions, 7 deletions
diff --git a/support/texlab/crates/texlab/src/main.rs b/support/texlab/crates/texlab/src/main.rs
index 08977ae96a..ceca02b7f7 100644
--- a/support/texlab/crates/texlab/src/main.rs
+++ b/support/texlab/crates/texlab/src/main.rs
@@ -1,9 +1,10 @@
use std::{fs::OpenOptions, io, path::PathBuf};
use anyhow::Result;
-use clap::{ArgAction, Parser};
+use clap::{ArgAction, Parser, Subcommand};
use log::LevelFilter;
use lsp_server::Connection;
+use lsp_types::Url;
use texlab::Server;
/// An implementation of the Language Server Protocol for LaTeX
@@ -21,20 +22,72 @@ struct Opts {
/// Write the logging output to FILE
#[clap(long, name = "FILE", value_parser)]
log_file: Option<PathBuf>,
+
+ #[clap(subcommand)]
+ command: Option<Command>,
+}
+
+#[derive(Debug, Subcommand)]
+enum Command {
+ /// Runs the language server in a editor context using STDIN and STDOUT.
+ Run,
+
+ /// Opens a document at a specific line.
+ ///
+ /// This command can be used to implement inverse search in an editor-agnostic way.
+ InverseSearch(InverseSearchOpts),
+}
+
+/// Options for the inverse search subcommand.
+#[derive(Debug, Parser)]
+struct InverseSearchOpts {
+ /// The path to the document to open.
+ #[clap(short, long, name = "FILE", value_parser)]
+ input: PathBuf,
+
+ /// The zero-based line number of the document to jump to.
+ #[clap(short, long)]
+ line: u32,
}
fn main() -> Result<()> {
let opts = Opts::parse();
- setup_logger(opts);
+ setup_logger(&opts);
+
+ match opts.command.unwrap_or(Command::Run) {
+ Command::Run => {
+ let (connection, threads) = Connection::stdio();
+ Server::exec(connection)?;
+ threads.join()?;
+ }
+ Command::InverseSearch(opts) => {
+ let Some(uri) = opts
+ .input
+ .canonicalize()
+ .ok()
+ .and_then(|path| Url::from_file_path(path).ok())
+ else {
+ eprintln!("Failed to convert input path to a URI.");
+ std::process::exit(-1);
+ };
+
+ let params = lsp_types::TextDocumentPositionParams::new(
+ lsp_types::TextDocumentIdentifier::new(uri),
+ lsp_types::Position::new(opts.line, 0),
+ );
- let (connection, threads) = Connection::stdio();
- Server::exec(connection)?;
- threads.join()?;
+ if let Err(why) = ipc::send_request(params) {
+ eprintln!("Failed to send inverse search request to the main instance. Is the server running?");
+ eprintln!("Details: {why:?}");
+ std::process::exit(-1);
+ }
+ }
+ }
Ok(())
}
-fn setup_logger(opts: Opts) {
+fn setup_logger(opts: &Opts) {
let verbosity_level = if !opts.quiet {
match opts.verbosity {
0 => LevelFilter::Error,
@@ -52,7 +105,7 @@ fn setup_logger(opts: Opts) {
.level(verbosity_level)
.chain(io::stderr());
- let logger = match opts.log_file {
+ let logger = match &opts.log_file {
Some(log_file) => logger.chain(
OpenOptions::new()
.write(true)