diff options
author | Norbert Preining <norbert@preining.info> | 2021-06-13 03:03:20 +0000 |
---|---|---|
committer | Norbert Preining <norbert@preining.info> | 2021-06-13 03:03:20 +0000 |
commit | 2ba4b1ac7860085c0b259aacb0d99bd2c730edbc (patch) | |
tree | 45f851c69d035dca1793ce55cce4783eb52b1dea /support | |
parent | 73dcf554624f325ec90d02815c36d92a33c2667f (diff) |
CTAN sync 202106130303
Diffstat (limited to 'support')
-rw-r--r-- | support/TeX4ht/source/ChangeLog | 8 | ||||
-rw-r--r-- | support/TeX4ht/source/mktex4ht-cnf.tex | 5 | ||||
-rw-r--r-- | support/TeX4ht/source/tex4ht-html4.tex | 5 | ||||
-rw-r--r-- | support/texlab/CHANGELOG.md | 21 | ||||
-rw-r--r-- | support/texlab/Cargo.lock | 21 | ||||
-rw-r--r-- | support/texlab/Cargo.toml | 3 | ||||
-rw-r--r-- | support/texlab/docs/options.md | 14 | ||||
-rw-r--r-- | support/texlab/docs/previewing.md | 76 | ||||
-rw-r--r-- | support/texlab/docs/tectonic.md | 4 | ||||
-rw-r--r-- | support/texlab/src/features.rs | 2 | ||||
-rw-r--r-- | support/texlab/src/features/build.rs | 277 | ||||
-rw-r--r-- | support/texlab/src/features/forward_search.rs | 14 | ||||
-rw-r--r-- | support/texlab/src/features/hover.rs | 2 | ||||
-rw-r--r-- | support/texlab/src/options.rs | 17 | ||||
-rw-r--r-- | support/texlab/src/server.rs | 114 |
15 files changed, 402 insertions, 181 deletions
diff --git a/support/TeX4ht/source/ChangeLog b/support/TeX4ht/source/ChangeLog index c93b99bd4a..34d97dfca7 100644 --- a/support/TeX4ht/source/ChangeLog +++ b/support/TeX4ht/source/ChangeLog @@ -1,3 +1,11 @@ +2021-06-12 Michal Hoftich <michal.h21@gmail.com> + + * tex4ht-html4.tex (html4.4ht): remove vertical space in \item items that + contain just one paragraph. + https://tug.org/pipermail/tex4ht/2021q2/002997.html + * tex4ht-4ht.tex (scrlayer.4ht): fix for runtime error when scrlayer checks + whether it can access current page style. + 2021-06-06 Karl Berry <karl@freefriends.org> * tex4ht-4ht.tex (moreverb.4ht, verbatim.4ht, fancyvrb.4ht, diff --git a/support/TeX4ht/source/mktex4ht-cnf.tex b/support/TeX4ht/source/mktex4ht-cnf.tex index bad50dd5bb..83a84aab4c 100644 --- a/support/TeX4ht/source/mktex4ht-cnf.tex +++ b/support/TeX4ht/source/mktex4ht-cnf.tex @@ -1,4 +1,4 @@ -% $Id: mktex4ht-cnf.tex 903 2021-04-16 15:02:57Z michal_h21 $ +% $Id: mktex4ht-cnf.tex 947 2021-06-12 16:27:33Z michal_h21 $ % Manually-maintained file, listing *.4ht files created by tex4ht-4ht.tex. % Read by tex4ht-cond4ht. % @@ -89,6 +89,7 @@ \AddFile{9}{texinfo} \AddFile{9}{doc} \AddFile{9}{holtxdoc} +\AddFile{9}{scrlayer} \AddFile{9}{scrbook} \AddFile{9}{scrartcl} \AddFile{9}{scrreprt} @@ -356,6 +357,8 @@ \AddFile{9}{parallel} \AddFile{9}{skak} \AddFile{9}{chessboard} +\AddFile{9}{menukeys} \AddFile{9}{animate} \AddFile{9}{sectionbreak} +\AddFile{9}{fontawesome5} % \AddFile{9}{mktex4ht} diff --git a/support/TeX4ht/source/tex4ht-html4.tex b/support/TeX4ht/source/tex4ht-html4.tex index 9bf0a4bcab..62591b9ef9 100644 --- a/support/TeX4ht/source/tex4ht-html4.tex +++ b/support/TeX4ht/source/tex4ht-html4.tex @@ -1,4 +1,4 @@ -% $Id: tex4ht-html4.tex 944 2021-06-03 09:29:05Z michal_h21 $ +% $Id: tex4ht-html4.tex 946 2021-06-12 09:15:22Z michal_h21 $ % Compile 4 times: latex tex4ht-html4 % Copy html4.4ht into the work directory before all but the last compilation. % @@ -2805,7 +2805,10 @@ such a case, we don't have proper nestings of environments. \<configure html4 latex\><<< \Css{li p.indent { text-indent: 0em }} \Css{li p:first-child{ margin-top:0em; }} +\Css{li p:first-child{ margin-bottom; }} \Css{li p:last-child, li div:last-child { margin-bottom:0.5em; }} +% fix for <li> with only one paragraph +\Css{li p:first-child{ margin-bottom:0; }} \Css{li p\string ~ul:last-child, li p\string ~ol:last-child{ margin-bottom:0.5em; }} >>> diff --git a/support/texlab/CHANGELOG.md b/support/texlab/CHANGELOG.md index 885fa24bc5..9be07281cd 100644 --- a/support/texlab/CHANGELOG.md +++ b/support/texlab/CHANGELOG.md @@ -5,6 +5,25 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [3.2.0] - 12.06.2021 + +### Added + +- Re-introduce `texlab.build.forwardSearchAfter` with a more reliable way of detecting the current line number. +- Re-introduce `texlab.build.onSave` due to popular request ([#427](https://github.com/latex-lsp/texlab/issues/427)). +- Re-introduce work done progress notifications for building. + +### Changed + +- Recommend `texlab.build.onSave` instead of `-pvc` in documentation. +- Do not rely on `.latexmkrc` for previewing anymore, + instead `texlab.build.forwardSearchAfter` can be used ([#440](https://github.com/latex-lsp/texlab/issues/440), [#436](https://github.com/latex-lsp/texlab/issues/436)). +- Deprecate `texlab.build.isContinuous` setting + +### Fixed + +- Fix conditional compilation of the `citation` feature. + ## [3.1.0] - 03.06.2021 ### Added @@ -12,7 +31,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Add `texlab.latexFormatter` setting to allow turning off `latexindent`. At the moment, `texlab.latexFormatter: texlab` is not implemented yet and does nothing. - Expose the `--local` flag of `latexindent` via `texlab.latexindent.local` setting ([#365](https://github.com/latex-lsp/texlab/issues/365)) -- Expose the `--modfiylinebreaks` flag of `latexindent` via `texlab.latexindent.modifyLineBreaks` setting ([#365](https://github.com/latex-lsp/texlab/issues/365)) +- Expose the `--modifylinebreaks` flag of `latexindent` via `texlab.latexindent.modifyLineBreaks` setting ([#365](https://github.com/latex-lsp/texlab/issues/365)) - Assign (unique) error codes to static analysis diagnostics. ### Fixed diff --git a/support/texlab/Cargo.lock b/support/texlab/Cargo.lock index 8ae7d7e49d..1a6f08988f 100644 --- a/support/texlab/Cargo.lock +++ b/support/texlab/Cargo.lock @@ -348,7 +348,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06ed27e177f16d65f0f0c22a213e17c696ace5dd64b14258b52f9417ccb52db4" dependencies = [ "cfg-if 1.0.0", - "crossbeam-utils 0.8.3", + "crossbeam-utils 0.8.5", ] [[package]] @@ -370,7 +370,7 @@ checksum = "94af6efb46fef72616855b036a624cf27ba656ffc9be1b9a3c931cfc7749a9a9" dependencies = [ "cfg-if 1.0.0", "crossbeam-epoch 0.9.3", - "crossbeam-utils 0.8.3", + "crossbeam-utils 0.8.5", ] [[package]] @@ -395,7 +395,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2584f639eb95fea8c798496315b297cf81b9b58b6d30ab066a75455333cf4b12" dependencies = [ "cfg-if 1.0.0", - "crossbeam-utils 0.8.3", + "crossbeam-utils 0.8.5", "lazy_static", "memoffset 0.6.3", "scopeguard", @@ -425,11 +425,10 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.3" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7e9d99fa91428effe99c5c6d4634cdeba32b8cf784fc428a2a687f61a952c49" +checksum = "d82cfc11ce7f2c3faef78d8a684447b40d503d9681acebed6cb728d45940c4db" dependencies = [ - "autocfg 1.0.1", "cfg-if 1.0.0", "lazy_static", ] @@ -1704,7 +1703,7 @@ checksum = "d78120e2c850279833f1dd3582f730c4ab53ed95aeaaaa862a2a5c71b1656d8e" dependencies = [ "crossbeam-channel 0.5.1", "crossbeam-deque 0.8.0", - "crossbeam-utils 0.8.3", + "crossbeam-utils 0.8.5", "lazy_static", "num_cpus", ] @@ -1788,7 +1787,7 @@ dependencies = [ "base64", "blake2b_simd", "constant_time_eq", - "crossbeam-utils 0.8.3", + "crossbeam-utils 0.8.5", ] [[package]] @@ -2156,7 +2155,7 @@ dependencies = [ [[package]] name = "texlab" -version = "3.1.0" +version = "3.2.0" dependencies = [ "anyhow", "bibutils-sys", @@ -2204,6 +2203,7 @@ dependencies = [ "typed-builder", "unindent", "url", + "uuid", ] [[package]] @@ -2459,6 +2459,9 @@ name = "uuid" version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" +dependencies = [ + "getrandom 0.2.2", +] [[package]] name = "v_escape" diff --git a/support/texlab/Cargo.toml b/support/texlab/Cargo.toml index 506b454b4a..790c5d8fe0 100644 --- a/support/texlab/Cargo.toml +++ b/support/texlab/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "texlab" description = "LaTeX Language Server" -version = "3.1.0" +version = "3.2.0" license = "GPL-3.0" readme = "README.md" authors = [ @@ -72,6 +72,7 @@ tempfile = "3.2.0" threadpool = "1.8.1" titlecase = "1.1.0" url = "2.2.2" +uuid = { version = "0.8.2", features = ["v4"] } [dev-dependencies] indoc = "1.0.3" diff --git a/support/texlab/docs/options.md b/support/texlab/docs/options.md index 3cc2edfd8a..e1a69c4996 100644 --- a/support/texlab/docs/options.md +++ b/support/texlab/docs/options.md @@ -46,9 +46,19 @@ The placeholder `%f` will be replaced by the server. --- -## texlab.build.isContinuous +## texlab.build.forwardSearchAfter -Set this property to true if the build arguments imply a continous build (like `latexmk -pvc`). +Set this property to `true` if you want to execute a forward search after a build. + +**Type:** `boolean` + +**Default value:** `false` + +--- + +## texlab.build.onSave + +Set this property to `true` if you want to compile the project after saving a file. **Type:** `boolean` diff --git a/support/texlab/docs/previewing.md b/support/texlab/docs/previewing.md index 16a047190b..0d9f35293c 100644 --- a/support/texlab/docs/previewing.md +++ b/support/texlab/docs/previewing.md @@ -1,19 +1,25 @@ # Previewing -We believe that previewing should be a concern of the build system. -With [`latexmk`](https://ctan.org/pkg/latexmk?lang=en), you can enable the preview feature by adding the `-pv` flag -to the [`texlab.build.args`](/docs/reference/configuration/#latexbuildargs) setting. -After that, the configured previewer will start on each rebuild of the document. -Alternatively, use the `-pvc` flag to tell the previewer to continuously check for updates, -instead of opening a new window each time a build completes. - -If you want to use [SyncTeX](http://www.tug.org/TUGboat/tb29-3/tb93laurens.pdf), -you need to configure the settings in the [`texlab.forwardSearch`](/docs/reference/configuration#latexforwardsearchexecutable) section -and configure your previewer to call your editor correctly. -A forward search can then be executed by invoking the [`texlab.forwardSearch`](/docs/reference/commands#latexforwardsearch) command. - -In the following sections, we will give configurations for popular viewers with `latexmk` and Visual Studio Code. -For other build systems and editors, please refer to their respective manuals. +`texlab` supports compiling LaTeX using a custom request (`textDocument/build`) +and by building a document after saving if configured to do so. +To enable building on save, simply set `texlab.build.onSave` to true. +Previewing can be configured in a variety of ways: + +1. If you are using `latexmk`, you can create a `.latexmkrc` file and call your viewer accordingly. + Afterwards, you can add the `-pv` flag to your `texlab.build.args`. + +2. If you want the PDF viewer to stay synchronized with the cursor position in your editor, + you can instruct `texlab` to execute a forward search after every build (`texlab.build.forwardSearchAfter`). + To do so, you need to enable [SyncTeX](http://www.tug.org/TUGboat/tb29-3/tb93laurens.pdf) + and update the `texlab.forwardSearch` configuration. + If you want to use this feature, we do _not_ recommend the `-pvc` flag + because `texlab` does not get notified by `latexmk` when a document gets built. + Instead, you can use `texlab.build.onSave`. + +In the following sections, we will give forward search configurations for several popular viewers +and Visual Studio Code. +However, these settings can easily be adapted to other editors. +If your viewer is not listed here, you can send us a pull request or create an issue. --- @@ -21,11 +27,6 @@ For other build systems and editors, please refer to their respective manuals. We highly recommend [SumatraPDF](https://www.sumatrapdfreader.org) on Windows because Adobe Reader locks the opened PDF file and will therefore prevent further builds. -To use [SumatraPDF](https://www.sumatrapdfreader.org) as previewer, add the following line to your `%USERPROFILE%/.latexmkrc` file: - -```perl -$pdf_previewer = 'start "C:\Program Files\SumatraPDF\SumatraPDF.exe" %O %S'; -``` ### Forward Search @@ -33,7 +34,7 @@ Add the following lines to your editor config: ```json { - "texlab.forwardSearch.executable": "C:/Program Files/SumatraPDF/SumatraPDF.exe", + "texlab.forwardSearch.executable": "C:/Users/{User}/AppData/Local/SumatraPDF/SumatraPDF.exe", "texlab.forwardSearch.args": [ "-reuse-instance", "%p", @@ -62,11 +63,6 @@ You can execute the search by pressing `Alt+DoubleClick` in the PDF document. The SyncTeX feature of [Evince](https://wiki.gnome.org/Apps/Evince) requires communication via D-Bus. In order to use it from the command line, install the [evince-synctex](https://github.com/latex-lsp/evince-synctex) script. -Then add the following line to your `~/.latexmkrc` file: - -```perl -$pdf_previewer = 'start evince-synctex %S "code -g %f:%l"'; -``` ### Forward Search @@ -88,12 +84,6 @@ You can execute the search by pressing `Ctrl+Click` in the PDF document. ## Okular -To use [Okular](https://okular.kde.org/) as previewer, add the following line to your `~/.latexmkrc` file: - -```perl -$pdf_previewer = 'start okular'; -``` - ### Forward Search Add the following lines to your editor config: @@ -119,12 +109,6 @@ You can execute the search by pressing `Shift+Click` in the PDF document. ## Zathura -To use [Zathura](https://pwmt.org/projects/zathura/) as previewer, add the following line to your `~/.latexmkrc` file: - -```perl -$pdf_previewer = 'start zathura'; -``` - ### Forward Search Add the following lines to your editor config: @@ -151,12 +135,6 @@ You can execute the search by pressing `Alt+Click` in the PDF document. ## qpdfview -To use [qpdfview](https://launchpad.net/qpdfview) as previewer, add the following line to your `~/.latexmkrc` file: - -```perl -$pdf_previewer = 'start qpdfview --unique %S'; -``` - ### Forward Search Add the following lines to your editor config: @@ -185,14 +163,6 @@ You can execute the search by pressing `Modifier+Click` in the PDF document. ## Skim We recommend [Skim](https://skim-app.sourceforge.io/) on macOS since it is the only native viewer that supports SyncTeX. -To use [Skim](https://skim-app.sourceforge.io/) as previewer, add the following line to your `~/.latexmkrc` file: - -```perl -$pdf_previewer = 'open -a Skim'; -``` - -If you want Skim to stay in the background after building, -you can add the `-g` option to the `open` arguments. Additionally, enable the "Reload automatically" setting in the Skim preferences (Skim -> Preferences -> Sync -> Check for file changes). @@ -209,9 +179,11 @@ Add the following lines to your editor config: If you want Skim to stay in the background after executing the forward search, you can add the `-g` option -to `latex.forwardSearch.args`. +to `texlab.forwardSearch.args`. ### Inverse Search Select the Visual Studio Code preset in the Skim preferences (Skim -> Preferences -> Sync -> PDF-TeX Sync support). You can execute the search by pressing `Shift+⌘+Click` in the PDF document. + +--- diff --git a/support/texlab/docs/tectonic.md b/support/texlab/docs/tectonic.md index 1e75c2d126..38e0a7d636 100644 --- a/support/texlab/docs/tectonic.md +++ b/support/texlab/docs/tectonic.md @@ -19,8 +19,8 @@ You can quickly get started by changing `.vscode/settings.json` in your workspac // uncomment the following line. //"--outdir out", ] - // OPTIONAL: The extension needs to be configured + // OPTIONAL: The server needs to be configured // to read the logs from the out directory as well. - // "latex.build.outputDirectory": "out", + // "texlab.auxDirectory": "out", } ``` diff --git a/support/texlab/src/features.rs b/support/texlab/src/features.rs index 09743c0035..36c406b6b9 100644 --- a/support/texlab/src/features.rs +++ b/support/texlab/src/features.rs @@ -25,7 +25,7 @@ pub use self::completion::{complete, CompletionItemData, COMPLETION_LIMIT}; #[cfg(feature = "semantic")] pub use self::semantic::{find_semantic_tokens_range, legend}; pub use self::{ - build::{build_document, BuildParams, BuildResult, BuildStatus}, + build::{BuildEngine, BuildParams, BuildResult, BuildStatus}, definition::goto_definition, folding::find_foldings, formatting::format_source_code, diff --git a/support/texlab/src/features/build.rs b/support/texlab/src/features/build.rs index c6a670528f..6953698a29 100644 --- a/support/texlab/src/features/build.rs +++ b/support/texlab/src/features/build.rs @@ -1,20 +1,29 @@ use std::{ - io::{self, BufRead, BufReader, Read}, + io::{BufRead, BufReader, Read}, path::Path, process::{Command, Stdio}, - thread, + sync::{Arc, Mutex}, + thread::{self, JoinHandle}, }; +use anyhow::Result; use cancellation::CancellationToken; +use chashmap::CHashMap; use crossbeam_channel::Sender; use encoding_rs_io::DecodeReaderBytesBuilder; -use lsp_types::TextDocumentIdentifier; +use lsp_types::{ + notification::{LogMessage, Progress}, + LogMessageParams, NumberOrString, Position, ProgressParams, ProgressParamsValue, + TextDocumentIdentifier, TextDocumentPositionParams, WorkDoneProgress, WorkDoneProgressBegin, + WorkDoneProgressCreateParams, WorkDoneProgressEnd, +}; use serde::{Deserialize, Serialize}; use serde_repr::{Deserialize_repr, Serialize_repr}; +use uuid::Uuid; -use crate::Options; +use crate::{client, req_queue::ReqQueue, ClientCapabilitiesExt, DocumentLanguage, Uri}; -use super::FeatureRequest; +use super::{forward_search, FeatureRequest}; #[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] @@ -25,10 +34,10 @@ pub struct BuildParams { #[derive(Debug, PartialEq, Eq, Clone, Copy, Serialize_repr, Deserialize_repr)] #[repr(i32)] pub enum BuildStatus { - Success = 0, - Error = 1, - Failure = 2, - Cancelled = 3, + SUCCESS = 0, + ERROR = 1, + FAILURE = 2, + CANCELLED = 3, } #[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)] @@ -37,78 +46,203 @@ pub struct BuildResult { pub status: BuildStatus, } -pub fn build_document( - request: FeatureRequest<BuildParams>, - _cancellation_token: &CancellationToken, - log_sender: Sender<String>, -) -> BuildResult { - let document = request - .subset - .documents - .iter() - .find(|document| { - if let Some(data) = document.data.as_latex() { - data.extras.has_document_environment - } else { - false - } - }) - .map(|document| document.as_ref()) - .unwrap_or_else(|| request.main_document()); +struct ProgressReporter<'a> { + supports_progress: bool, + req_queue: &'a Mutex<ReqQueue>, + lsp_sender: Sender<lsp_server::Message>, + token: &'a str, +} - if document.uri.scheme() != "file" { - return BuildResult { - status: BuildStatus::Failure, +impl<'a> ProgressReporter<'a> { + pub fn start(&self, uri: &Uri) -> Result<()> { + if self.supports_progress { + client::send_request::<lsp_types::request::WorkDoneProgressCreate>( + self.req_queue, + &self.lsp_sender, + WorkDoneProgressCreateParams { + token: NumberOrString::String(self.token.to_string()), + }, + )?; + client::send_notification::<Progress>( + &self.lsp_sender, + ProgressParams { + token: NumberOrString::String(self.token.to_string()), + value: ProgressParamsValue::WorkDone(WorkDoneProgress::Begin( + WorkDoneProgressBegin { + title: "Building".to_string(), + message: Some(uri.as_str().to_string()), + cancellable: Some(false), + percentage: None, + }, + )), + }, + )?; }; + Ok(()) } - log::info!("Building document {}", document.uri.as_str()); - - let options = { request.context.options.read().unwrap().clone() }; +} - let status = match build_internal(&document.uri.to_file_path().unwrap(), &options, log_sender) { - Ok(true) => BuildStatus::Success, - Ok(false) => BuildStatus::Error, - Err(why) => { - log::error!("Failed to execute textDocument/build: {}", why); - BuildStatus::Failure +impl<'a> Drop for ProgressReporter<'a> { + fn drop(&mut self) { + if self.supports_progress { + let _ = client::send_notification::<Progress>( + &self.lsp_sender, + ProgressParams { + token: NumberOrString::String(self.token.to_string()), + value: ProgressParamsValue::WorkDone(WorkDoneProgress::End( + WorkDoneProgressEnd { message: None }, + )), + }, + ); } - }; - BuildResult { status } + } +} + +#[derive(Default)] +pub struct BuildEngine { + lock: Mutex<()>, + pub positions_by_uri: CHashMap<Arc<Uri>, Position>, } -fn build_internal(path: &Path, options: &Options, log_sender: Sender<String>) -> io::Result<bool> { - let build_dir = options - .root_directory - .as_ref() - .map(AsRef::as_ref) - .or_else(|| path.parent()) - .unwrap(); - - let args: Vec<_> = options - .build - .args() - .into_iter() - .map(|arg| replace_placeholder(arg, path)) - .collect(); - - let mut process = Command::new(options.build.executable()) - .args(args) - .stdin(Stdio::null()) - .stdout(Stdio::piped()) - .stderr(Stdio::piped()) - .current_dir(build_dir) - .spawn()?; +impl BuildEngine { + pub fn build( + &self, + request: FeatureRequest<BuildParams>, + cancellation_token: &CancellationToken, + req_queue: &Mutex<ReqQueue>, + lsp_sender: &Sender<lsp_server::Message>, + ) -> Result<BuildResult> { + let lock = self.lock.lock().unwrap(); - track_output(process.stdout.take().unwrap(), log_sender.clone()); - track_output(process.stderr.take().unwrap(), log_sender.clone()); + let document = request + .subset + .documents + .iter() + .find(|document| { + if let Some(data) = document.data.as_latex() { + data.extras.has_document_environment + } else { + false + } + }) + .map(|document| document.as_ref()) + .unwrap_or_else(|| request.main_document()); - if !options.build.is_continuous { - process.wait().map(|status| status.success()) - } else { - Ok(true) + if document.language() != DocumentLanguage::Latex { + return Ok(BuildResult { + status: BuildStatus::SUCCESS, + }); + } + + if document.uri.scheme() != "file" { + return Ok(BuildResult { + status: BuildStatus::FAILURE, + }); + } + let path = document.uri.to_file_path().unwrap(); + + let supports_progress = { + request + .context + .client_capabilities + .lock() + .unwrap() + .has_work_done_progress_support() + }; + + let token = format!("texlab-build-{}", Uuid::new_v4()); + let progress_reporter = ProgressReporter { + supports_progress, + req_queue, + lsp_sender: lsp_sender.clone(), + token: &token, + }; + progress_reporter.start(&document.uri)?; + + let options = { request.context.options.read().unwrap().clone() }; + + let build_dir = options + .root_directory + .as_ref() + .map(AsRef::as_ref) + .or_else(|| path.parent()) + .unwrap(); + + let args: Vec<_> = options + .build + .args() + .into_iter() + .map(|arg| replace_placeholder(arg, &path)) + .collect(); + + let mut process = Command::new(options.build.executable()) + .args(args) + .stdin(Stdio::null()) + .stdout(Stdio::piped()) + .stderr(Stdio::piped()) + .current_dir(build_dir) + .spawn()?; + + let log_handle = capture_output(&mut process, lsp_sender); + let success = process.wait().map(|status| status.success())?; + log_handle.join().unwrap(); + let status = if success { + BuildStatus::SUCCESS + } else { + BuildStatus::ERROR + }; + + drop(progress_reporter); + drop(lock); + + if options.build.forward_search_after { + let request = FeatureRequest { + params: TextDocumentPositionParams { + position: self + .positions_by_uri + .get(&request.main_document().uri) + .map(|guard| guard.clone()) + .unwrap_or_default(), + text_document: TextDocumentIdentifier::new( + request.main_document().uri.as_ref().clone().into(), + ), + }, + context: request.context, + workspace: request.workspace, + subset: request.subset, + }; + forward_search::execute_forward_search(request, cancellation_token); + } + + Ok(BuildResult { status }) } } +fn capture_output( + process: &mut std::process::Child, + lsp_sender: &Sender<lsp_server::Message>, +) -> JoinHandle<()> { + let (log_sender, log_receiver) = crossbeam_channel::unbounded(); + track_output(process.stdout.take().unwrap(), log_sender.clone()); + track_output(process.stderr.take().unwrap(), log_sender); + let log_handle = { + let lsp_sender = lsp_sender.clone(); + thread::spawn(move || { + for message in &log_receiver { + client::send_notification::<LogMessage>( + &lsp_sender, + LogMessageParams { + message, + typ: lsp_types::MessageType::Log, + }, + ) + .unwrap(); + } + }) + }; + log_handle +} + fn replace_placeholder(arg: String, file: &Path) -> String { if arg.starts_with('"') || arg.ends_with('"') { arg @@ -117,7 +251,7 @@ fn replace_placeholder(arg: String, file: &Path) -> String { } } -fn track_output(output: impl Read + Send + 'static, sender: Sender<String>) { +fn track_output(output: impl Read + Send + 'static, sender: Sender<String>) -> JoinHandle<()> { let reader = BufReader::new( DecodeReaderBytesBuilder::new() .encoding(Some(encoding_rs::UTF_8)) @@ -125,9 +259,10 @@ fn track_output(output: impl Read + Send + 'static, sender: Sender<String>) { .strip_bom(true) .build(output), ); + thread::spawn(move || { for line in reader.lines() { sender.send(line.unwrap()).unwrap(); } - }); + }) } diff --git a/support/texlab/src/features/forward_search.rs b/support/texlab/src/features/forward_search.rs index 39470a64ec..4a54b8a52a 100644 --- a/support/texlab/src/features/forward_search.rs +++ b/support/texlab/src/features/forward_search.rs @@ -15,10 +15,10 @@ use super::FeatureRequest; #[derive(Debug, PartialEq, Eq, Clone, Copy, Serialize_repr, Deserialize_repr)] #[repr(i32)] pub enum ForwardSearchStatus { - Success = 0, - Error = 1, - Failure = 2, - Unconfigured = 3, + SUCCESS = 0, + ERROR = 1, + FAILURE = 2, + UNCONFIGURED = 3, } #[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)] @@ -43,7 +43,7 @@ pub fn execute_forward_search( if options.executable.is_none() || options.args.is_none() { return Some(ForwardSearchResult { - status: ForwardSearchStatus::Unconfigured, + status: ForwardSearchStatus::UNCONFIGURED, }); } @@ -87,10 +87,10 @@ pub fn execute_forward_search( .collect(); let status = match run_process(options.executable.unwrap(), args) { - Ok(()) => ForwardSearchStatus::Success, + Ok(()) => ForwardSearchStatus::SUCCESS, Err(why) => { error!("Unable to execute forward search: {}", why); - ForwardSearchStatus::Failure + ForwardSearchStatus::FAILURE } }; Some(ForwardSearchResult { status }) diff --git a/support/texlab/src/features/hover.rs b/support/texlab/src/features/hover.rs index a78978bc33..efd7555a57 100644 --- a/support/texlab/src/features/hover.rs +++ b/support/texlab/src/features/hover.rs @@ -1,4 +1,4 @@ -#[cfg(feature = "citeproc")] +#[cfg(feature = "citation")] mod citation; mod component; mod entry_type; diff --git a/support/texlab/src/options.rs b/support/texlab/src/options.rs index 2626143e18..20f92a90f4 100644 --- a/support/texlab/src/options.rs +++ b/support/texlab/src/options.rs @@ -75,6 +75,12 @@ pub struct BuildOptions { #[serde(default)] pub is_continuous: bool, + + #[serde(default)] + pub on_save: bool, + + #[serde(default)] + pub forward_search_after: bool, } impl BuildOptions { @@ -99,6 +105,17 @@ impl BuildOptions { #[derive(Debug, PartialEq, Eq, Clone, Default, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] +pub struct ViewerOptions { + #[serde(default)] + pub enabled: bool, + + pub executable: Option<String>, + + pub args: Option<String>, +} + +#[derive(Debug, PartialEq, Eq, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] pub struct ChktexOptions { #[serde(default)] pub on_open_and_save: bool, diff --git a/support/texlab/src/server.rs b/support/texlab/src/server.rs index 5a78d5e2e2..6806e5f8e5 100644 --- a/support/texlab/src/server.rs +++ b/support/texlab/src/server.rs @@ -1,18 +1,17 @@ use std::{ path::PathBuf, sync::{Arc, Mutex}, - thread, }; use anyhow::Result; use cancellation::{CancellationToken, CancellationTokenSource}; use crossbeam_channel::Sender; -use log::{info, warn}; +use log::{error, info, warn}; use lsp_server::{Connection, ErrorCode, Message, RequestId}; use lsp_types::{ notification::{ Cancel, DidChangeConfiguration, DidChangeTextDocument, DidOpenTextDocument, - DidSaveTextDocument, LogMessage, PublishDiagnostics, + DidSaveTextDocument, PublishDiagnostics, }, request::{ DocumentLinkRequest, FoldingRangeRequest, Formatting, GotoDefinition, PrepareRenameRequest, @@ -37,10 +36,10 @@ use crate::{ dispatch::{NotificationDispatcher, RequestDispatcher}, distro::Distribution, features::{ - build_document, find_all_references, find_document_highlights, find_document_links, - find_document_symbols, find_foldings, find_hover, find_workspace_symbols, - format_source_code, goto_definition, prepare_rename_all, rename_all, BuildParams, - BuildResult, FeatureRequest, ForwardSearchResult, + find_all_references, find_document_highlights, find_document_links, find_document_symbols, + find_foldings, find_hover, find_workspace_symbols, format_source_code, goto_definition, + prepare_rename_all, rename_all, BuildEngine, BuildParams, BuildResult, BuildStatus, + FeatureRequest, ForwardSearchResult, }, req_queue::{IncomingData, ReqQueue}, DocumentLanguage, ServerContext, Uri, Workspace, WorkspaceSource, @@ -55,6 +54,7 @@ pub struct Server { chktex_debouncer: DiagnosticsDebouncer, pool: ThreadPool, load_resolver: bool, + build_engine: Arc<BuildEngine>, } impl Server { @@ -83,6 +83,7 @@ impl Server { chktex_debouncer, pool: threadpool::Builder::new().build(), load_resolver, + build_engine: Arc::default(), }) } @@ -257,7 +258,24 @@ impl Server { fn did_change(&self, mut params: DidChangeTextDocumentParams) -> Result<()> { let uri = params.text_document.uri.into(); assert_eq!(params.content_changes.len(), 1); - let text = params.content_changes.pop().unwrap().text; + let old_document = self.workspace.get(&uri); + let old_text = old_document.as_ref().map(|document| document.text.as_str()); + let new_text = params.content_changes.pop().unwrap().text; + + let uri = Arc::new(uri); + + let line = match old_text { + Some(old_text) => old_text + .lines() + .zip(new_text.lines()) + .position(|(a, b)| a != b) + .unwrap_or_default() as u32, + None => 0, + }; + self.build_engine + .positions_by_uri + .insert(Arc::clone(&uri), Position::new(line, 0)); + let language = self .workspace .get(&uri) @@ -266,7 +284,7 @@ impl Server { let document = self .workspace - .open(Arc::new(uri), text, language, WorkspaceSource::Client); + .open(uri, new_text, language, WorkspaceSource::Client); let should_lint = { self.context.options.read().unwrap().chktex.on_edit }; if let Some(document) = self @@ -287,6 +305,36 @@ impl Server { fn did_save(&self, params: DidSaveTextDocumentParams) -> Result<()> { let uri = params.text_document.uri.into(); + + let should_build = { self.context.options.read().unwrap().build.on_save }; + if let Some(request) = + self.workspace + .get(&uri) + .filter(|_| should_build) + .and_then(|document| { + self.feature_request( + Arc::clone(&document.uri), + BuildParams { + text_document: TextDocumentIdentifier::new(uri.clone().into()), + }, + ) + }) + { + let lsp_sender = self.connection.sender.clone(); + let req_queue = Arc::clone(&self.req_queue); + let build_engine = Arc::clone(&self.build_engine); + self.pool.execute(move || { + build_engine + .build(request, CancellationToken::none(), &req_queue, &lsp_sender) + .unwrap_or_else(|why| { + error!("Build failed: {}", why); + BuildResult { + status: BuildStatus::FAILURE, + } + }); + }); + } + let should_lint = { self.context.options.read().unwrap().chktex.on_open_and_save }; if let Some(document) = self.workspace.get(&uri).filter(|_| should_lint) { self.chktex_debouncer @@ -430,6 +478,11 @@ impl Server { .clone() .into(), ); + + self.build_engine + .positions_by_uri + .insert(Arc::clone(&uri), params.text_document_position.position); + self.handle_feature_request(id, params, uri, token, crate::features::complete)?; Ok(()) } @@ -452,7 +505,7 @@ impl Server { .documentation(&item.label) .map(Documentation::MarkupContent); } - #[cfg(feature = "citeproc")] + #[cfg(feature = "citation")] crate::features::CompletionItemData::Citation { uri, key } => { if let Some(document) = workspace.get(&uri) { if let Some(data) = document.data.as_bibtex() { @@ -519,6 +572,11 @@ impl Server { .clone() .into(), ); + self.build_engine.positions_by_uri.insert( + Arc::clone(&uri), + params.text_document_position_params.position, + ); + self.handle_feature_request(id, params, uri, token, find_hover)?; Ok(()) } @@ -635,23 +693,17 @@ impl Server { ) -> Result<()> { let uri = Arc::new(params.text_document.uri.clone().into()); let lsp_sender = self.connection.sender.clone(); - self.handle_feature_request(id, params, uri, token, |request, token| { - let (log_sender, log_receiver) = crossbeam_channel::unbounded(); - - thread::spawn(move || { - for message in &log_receiver { - send_notification::<LogMessage>( - &lsp_sender, - LogMessageParams { - message, - typ: MessageType::Log, - }, - ) - .unwrap(); - } - }); - - build_document(request, token, log_sender) + let req_queue = Arc::clone(&self.req_queue); + let build_engine = Arc::clone(&self.build_engine); + self.handle_feature_request(id, params, uri, token, move |request, token| { + build_engine + .build(request, token, &req_queue, &lsp_sender) + .unwrap_or_else(|why| { + error!("Build failed: {}", why); + BuildResult { + status: BuildStatus::FAILURE, + } + }) })?; Ok(()) } @@ -745,11 +797,9 @@ impl Server { Message::Response(response) => { let mut req_queue = self.req_queue.lock().unwrap(); let data = req_queue.outgoing.complete(response.id); - let result = match response.result { - Some(result) => Ok(result), - None => Err(response - .error - .expect("response without result or error received")), + let result = match response.error { + Some(error) => Err(error), + None => Ok(response.result.unwrap_or_default()), }; data.sender.send(result)?; } |