summaryrefslogtreecommitdiff
path: root/support
diff options
context:
space:
mode:
authorNorbert Preining <norbert@preining.info>2021-06-13 03:03:20 +0000
committerNorbert Preining <norbert@preining.info>2021-06-13 03:03:20 +0000
commit2ba4b1ac7860085c0b259aacb0d99bd2c730edbc (patch)
tree45f851c69d035dca1793ce55cce4783eb52b1dea /support
parent73dcf554624f325ec90d02815c36d92a33c2667f (diff)
CTAN sync 202106130303
Diffstat (limited to 'support')
-rw-r--r--support/TeX4ht/source/ChangeLog8
-rw-r--r--support/TeX4ht/source/mktex4ht-cnf.tex5
-rw-r--r--support/TeX4ht/source/tex4ht-html4.tex5
-rw-r--r--support/texlab/CHANGELOG.md21
-rw-r--r--support/texlab/Cargo.lock21
-rw-r--r--support/texlab/Cargo.toml3
-rw-r--r--support/texlab/docs/options.md14
-rw-r--r--support/texlab/docs/previewing.md76
-rw-r--r--support/texlab/docs/tectonic.md4
-rw-r--r--support/texlab/src/features.rs2
-rw-r--r--support/texlab/src/features/build.rs277
-rw-r--r--support/texlab/src/features/forward_search.rs14
-rw-r--r--support/texlab/src/features/hover.rs2
-rw-r--r--support/texlab/src/options.rs17
-rw-r--r--support/texlab/src/server.rs114
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)?;
}