summaryrefslogtreecommitdiff
path: root/support/texlab/crates
diff options
context:
space:
mode:
authorNorbert Preining <norbert@preining.info>2024-07-07 03:01:19 +0000
committerNorbert Preining <norbert@preining.info>2024-07-07 03:01:19 +0000
commita8098e7a183f670ff9b54d26bfc95b819c184fdc (patch)
treef7bbb216eca902046c30dde37b65d04cecf61297 /support/texlab/crates
parente2608dafc14bd92dad21c0a666cc054d0d030e40 (diff)
CTAN sync 202407070301
Diffstat (limited to 'support/texlab/crates')
-rw-r--r--support/texlab/crates/base-db/Cargo.toml8
-rw-r--r--support/texlab/crates/base-db/src/deps/graph.rs78
-rw-r--r--support/texlab/crates/base-db/src/document.rs12
-rw-r--r--support/texlab/crates/bibtex-utils/Cargo.toml4
-rw-r--r--support/texlab/crates/citeproc/Cargo.toml4
-rw-r--r--support/texlab/crates/commands/Cargo.toml8
-rw-r--r--support/texlab/crates/commands/src/dep_graph.rs1
-rw-r--r--support/texlab/crates/completion-data/Cargo.toml8
-rw-r--r--support/texlab/crates/completion/Cargo.toml2
-rw-r--r--support/texlab/crates/definition/Cargo.toml4
-rw-r--r--support/texlab/crates/diagnostics/Cargo.toml8
-rw-r--r--support/texlab/crates/distro/Cargo.toml2
-rw-r--r--support/texlab/crates/distro/src/language.rs2
-rw-r--r--support/texlab/crates/inlay-hints/Cargo.toml2
-rw-r--r--support/texlab/crates/ipc/Cargo.toml8
-rw-r--r--support/texlab/crates/line-index/Cargo.toml2
-rw-r--r--support/texlab/crates/parser/Cargo.toml8
-rw-r--r--support/texlab/crates/parser/src/bibtex.rs54
-rw-r--r--support/texlab/crates/parser/src/bibtex/tests.rs277
-rw-r--r--support/texlab/crates/parser/src/file_list.rs44
-rw-r--r--support/texlab/crates/parser/src/latex/lexer/types.rs49
-rw-r--r--support/texlab/crates/parser/src/lib.rs6
-rw-r--r--support/texlab/crates/parser/src/util.rs52
-rw-r--r--support/texlab/crates/references/Cargo.toml2
-rw-r--r--support/texlab/crates/rename/Cargo.toml2
-rw-r--r--support/texlab/crates/symbols/Cargo.toml4
-rw-r--r--support/texlab/crates/symbols/src/document.rs1
-rw-r--r--support/texlab/crates/syntax/Cargo.toml3
-rw-r--r--support/texlab/crates/syntax/src/file_list.rs10
-rw-r--r--support/texlab/crates/syntax/src/lib.rs1
-rw-r--r--support/texlab/crates/texlab/Cargo.toml16
-rw-r--r--support/texlab/crates/texlab/src/features/formatting.rs3
-rw-r--r--support/texlab/crates/texlab/src/util.rs59
33 files changed, 604 insertions, 140 deletions
diff --git a/support/texlab/crates/base-db/Cargo.toml b/support/texlab/crates/base-db/Cargo.toml
index ca477c496c..547ba2ad77 100644
--- a/support/texlab/crates/base-db/Cargo.toml
+++ b/support/texlab/crates/base-db/Cargo.toml
@@ -10,16 +10,16 @@ rust-version.workspace = true
bibtex-utils = { path = "../bibtex-utils" }
dirs = "5.0.1"
distro = { path = "../distro" }
-itertools = "0.12.1"
+itertools = "0.13.0"
line-index = { path = "../line-index" }
-log = "0.4.21"
+log = "0.4.22"
notify = "6.0.1"
once_cell = "1.19.0"
parser = { path = "../parser" }
percent-encoding = "2.3.0"
-regex = "1.10.4"
+regex = "1.10.5"
rowan = "0.15.15"
-rustc-hash = "1.1.0"
+rustc-hash = "2.0.0"
shellexpand = "3.1.0"
syntax = { path = "../syntax" }
titlecase = "3.0.0"
diff --git a/support/texlab/crates/base-db/src/deps/graph.rs b/support/texlab/crates/base-db/src/deps/graph.rs
index 4b2399b7f8..580e2865d6 100644
--- a/support/texlab/crates/base-db/src/deps/graph.rs
+++ b/support/texlab/crates/base-db/src/deps/graph.rs
@@ -1,4 +1,4 @@
-use std::{ffi::OsStr, path::PathBuf, rc::Rc};
+use std::{ffi::OsStr, path::PathBuf, rc::Rc, sync::Arc};
use distro::Language;
use itertools::Itertools;
@@ -23,6 +23,7 @@ pub struct Edge {
#[derive(Debug, PartialEq, Eq, Clone, Hash)]
pub enum EdgeData {
DirectLink(Box<DirectLinkData>),
+ FileList(Arc<ProjectRoot>),
AdditionalFiles,
Artifact,
}
@@ -74,6 +75,7 @@ impl Graph {
if visited.insert(edge.target.clone()) {
let new_root = match &edge.data {
EdgeData::DirectLink(data) => data.new_root.clone(),
+ EdgeData::FileList(root) => Some(root.as_ref().clone()),
_ => None,
};
@@ -101,6 +103,7 @@ impl Graph {
self.add_direct_links(workspace, start);
self.add_artifacts(workspace, start);
self.add_additional_files(workspace, start);
+ self.add_file_list_links(workspace, start);
}
fn add_additional_files(&mut self, workspace: &Workspace, start: Start) {
@@ -120,6 +123,43 @@ impl Graph {
}
}
+ fn add_file_list_links(&mut self, workspace: &Workspace, start: Start) -> Option<()> {
+ let file_list = start.source.data.as_file_list()?;
+ let home_dir = HOME_DIR.as_deref();
+
+ let working_dir = file_list
+ .working_dir
+ .as_deref()
+ .and_then(|dir| Url::from_directory_path(dir).ok());
+
+ let working_dir = working_dir.as_ref().unwrap_or(&start.source.dir);
+ let new_root = Arc::new(ProjectRoot::from_config(workspace, working_dir));
+
+ for target_uri in file_list
+ .inputs
+ .iter()
+ .chain(file_list.outputs.iter())
+ .filter(|path| {
+ path.is_relative()
+ || Language::from_path(&path) == Some(Language::Bib)
+ || home_dir.map_or(false, |home_dir| path.starts_with(home_dir))
+ })
+ .filter_map(|path| working_dir.join(path.to_str()?).ok())
+ {
+ if workspace.lookup(&target_uri).is_some() {
+ self.edges.push(Edge {
+ source: start.source.uri.clone(),
+ target: target_uri,
+ data: EdgeData::FileList(Arc::clone(&new_root)),
+ });
+ } else {
+ self.missing.push(target_uri);
+ }
+ }
+
+ Some(())
+ }
+
fn add_direct_links(&mut self, workspace: &Workspace, start: Start) -> Option<()> {
let data = start.source.data.as_tex()?;
@@ -169,7 +209,7 @@ impl Graph {
.base_dir
.as_deref()
.and_then(|path| start.root.src_dir.join(path).ok())
- .map(|dir| ProjectRoot::walk_and_find(workspace, &dir));
+ .map(|dir| ProjectRoot::from_config(workspace, &dir));
let link_data = DirectLinkData {
link: link.clone(),
@@ -197,27 +237,33 @@ impl Graph {
}
let root = start.root;
- let relative_path = root.compile_dir.make_relative(&start.source.uri).unwrap();
-
- self.add_artifact(
- workspace,
- start.source,
- &root.aux_dir.join(&relative_path).unwrap(),
- "aux",
- );
+ self.add_artifact_group(workspace, start, &root.aux_dir, "aux");
+ self.add_artifact_group(workspace, start, &root.log_dir, "log");
+ self.add_artifact_group(workspace, start, &root.aux_dir, "fls");
+ }
- self.add_artifact(workspace, start.source, &root.aux_dir, "aux");
- self.add_artifact(workspace, start.source, &root.compile_dir, "aux");
+ fn add_artifact_group(
+ &mut self,
+ workspace: &Workspace,
+ start: Start,
+ dir: &Url,
+ extension: &str,
+ ) {
+ let relative_path = start
+ .root
+ .compile_dir
+ .make_relative(&start.source.uri)
+ .unwrap();
self.add_artifact(
workspace,
start.source,
- &root.log_dir.join(&relative_path).unwrap(),
- "log",
+ &dir.join(&relative_path).unwrap(),
+ extension,
);
- self.add_artifact(workspace, start.source, &root.log_dir, "log");
- self.add_artifact(workspace, start.source, &root.compile_dir, "log");
+ self.add_artifact(workspace, start.source, &dir, extension);
+ self.add_artifact(workspace, start.source, &start.root.compile_dir, extension);
}
fn add_artifact(
diff --git a/support/texlab/crates/base-db/src/document.rs b/support/texlab/crates/base-db/src/document.rs
index afb5869d69..6fdcf30c16 100644
--- a/support/texlab/crates/base-db/src/document.rs
+++ b/support/texlab/crates/base-db/src/document.rs
@@ -3,7 +3,7 @@ use std::path::PathBuf;
use distro::Language;
use line_index::{LineCol, LineIndex};
use rowan::TextRange;
-use syntax::{bibtex, latex, latexmkrc::LatexmkrcData, BuildError};
+use syntax::{bibtex, file_list::FileList, latex, latexmkrc::LatexmkrcData, BuildError};
use url::Url;
use crate::{semantics, Config};
@@ -89,6 +89,7 @@ impl Document {
DocumentData::Latexmkrc(data)
}
Language::Tectonic => DocumentData::Tectonic,
+ Language::FileList => DocumentData::FileList(parser::parse_file_list(&text)),
};
Self {
@@ -146,6 +147,7 @@ pub enum DocumentData {
Root,
Latexmkrc(LatexmkrcData),
Tectonic,
+ FileList(FileList),
}
impl DocumentData {
@@ -188,6 +190,14 @@ impl DocumentData {
None
}
}
+
+ pub fn as_file_list(&self) -> Option<&FileList> {
+ if let DocumentData::FileList(data) = self {
+ Some(data)
+ } else {
+ None
+ }
+ }
}
#[derive(Debug, Clone)]
diff --git a/support/texlab/crates/bibtex-utils/Cargo.toml b/support/texlab/crates/bibtex-utils/Cargo.toml
index c20508107c..88ba2d3a37 100644
--- a/support/texlab/crates/bibtex-utils/Cargo.toml
+++ b/support/texlab/crates/bibtex-utils/Cargo.toml
@@ -9,9 +9,9 @@ rust-version.workspace = true
[dependencies]
chrono = { version = "0.4.38", default-features = false, features = ["std"] }
human_name = "2.0.3"
-itertools = "0.12.1"
+itertools = "0.13.0"
rowan = "0.15.15"
-rustc-hash = "1.1.0"
+rustc-hash = "2.0.0"
syntax = { path = "../syntax" }
unicode-normalization = "0.1.23"
diff --git a/support/texlab/crates/citeproc/Cargo.toml b/support/texlab/crates/citeproc/Cargo.toml
index 9e187f88e6..c87ab14b0e 100644
--- a/support/texlab/crates/citeproc/Cargo.toml
+++ b/support/texlab/crates/citeproc/Cargo.toml
@@ -10,9 +10,9 @@ rust-version.workspace = true
bibtex-utils = { path = "../bibtex-utils" }
base-db = { path = "../base-db" }
isocountry = "0.3.2"
-itertools = "0.12.1"
+itertools = "0.13.0"
rowan = "0.15.15"
-rustc-hash = "1.1.0"
+rustc-hash = "2.0.0"
syntax = { path = "../syntax" }
titlecase = "3.0.0"
unicode-normalization = "0.1.23"
diff --git a/support/texlab/crates/commands/Cargo.toml b/support/texlab/crates/commands/Cargo.toml
index 6e415f20d6..6507efb3b8 100644
--- a/support/texlab/crates/commands/Cargo.toml
+++ b/support/texlab/crates/commands/Cargo.toml
@@ -10,12 +10,12 @@ rust-version.workspace = true
anyhow = "1.0.86"
base-db = { path = "../base-db" }
bstr = "1.9.1"
-crossbeam-channel = "0.5.12"
-itertools = "0.12.1"
+crossbeam-channel = "0.5.13"
+itertools = "0.13.0"
libc = "0.2.155"
-log = "0.4.21"
+log = "0.4.22"
rowan = "0.15.15"
-rustc-hash = "1.1.0"
+rustc-hash = "2.0.0"
syntax = { path = "../syntax" }
thiserror = "1.0.61"
url = "2.5.0"
diff --git a/support/texlab/crates/commands/src/dep_graph.rs b/support/texlab/crates/commands/src/dep_graph.rs
index fe9ff3829c..86b49da0ac 100644
--- a/support/texlab/crates/commands/src/dep_graph.rs
+++ b/support/texlab/crates/commands/src/dep_graph.rs
@@ -48,6 +48,7 @@ pub fn show_dependency_graph(workspace: &Workspace) -> Result<String> {
base_db::deps::EdgeData::DirectLink(data) => &data.link.path.text,
base_db::deps::EdgeData::AdditionalFiles => "<project>",
base_db::deps::EdgeData::Artifact => "<artifact>",
+ base_db::deps::EdgeData::FileList(_) => "<fls>",
};
writeln!(&mut writer, "\t{source} -> {target} [label=\"{label}\"];")?;
diff --git a/support/texlab/crates/completion-data/Cargo.toml b/support/texlab/crates/completion-data/Cargo.toml
index 970cd6a578..6dbb7d4086 100644
--- a/support/texlab/crates/completion-data/Cargo.toml
+++ b/support/texlab/crates/completion-data/Cargo.toml
@@ -8,11 +8,11 @@ rust-version.workspace = true
[dependencies]
flate2 = "1.0.30"
-itertools = "0.12.1"
+itertools = "0.13.0"
once_cell = "1.19.0"
-rustc-hash = "1.1.0"
-serde = { version = "1.0.202", features = ["derive"] }
-serde_json = "1.0.117"
+rustc-hash = "2.0.0"
+serde = { version = "1.0.203", features = ["derive"] }
+serde_json = "1.0.119"
[lib]
doctest = false
diff --git a/support/texlab/crates/completion/Cargo.toml b/support/texlab/crates/completion/Cargo.toml
index 6469b5f004..f98f12260b 100644
--- a/support/texlab/crates/completion/Cargo.toml
+++ b/support/texlab/crates/completion/Cargo.toml
@@ -13,7 +13,7 @@ fuzzy-matcher = { version = "0.3.7", features = ["compact"] }
line-index = { path = "../line-index" }
rayon = "1.10.0"
rowan = "0.15.15"
-rustc-hash = "1.1.0"
+rustc-hash = "2.0.0"
syntax = { path = "../syntax" }
url = "2.5.0"
diff --git a/support/texlab/crates/definition/Cargo.toml b/support/texlab/crates/definition/Cargo.toml
index 63ba15c308..254bea0314 100644
--- a/support/texlab/crates/definition/Cargo.toml
+++ b/support/texlab/crates/definition/Cargo.toml
@@ -9,11 +9,11 @@ rust-version.workspace = true
[dependencies]
base-db = { path = "../base-db" }
rowan = "0.15.15"
-rustc-hash = "1.1.0"
+rustc-hash = "2.0.0"
syntax = { path = "../syntax" }
[dev-dependencies]
-itertools = "0.12.1"
+itertools = "0.13.0"
test-utils = { path = "../test-utils" }
[lib]
diff --git a/support/texlab/crates/diagnostics/Cargo.toml b/support/texlab/crates/diagnostics/Cargo.toml
index 1cb09fdec9..37e39280ad 100644
--- a/support/texlab/crates/diagnostics/Cargo.toml
+++ b/support/texlab/crates/diagnostics/Cargo.toml
@@ -10,14 +10,14 @@ rust-version.workspace = true
base-db = { path = "../base-db" }
encoding_rs = "0.8.34"
encoding_rs_io = "0.1.7"
-itertools = "0.12.1"
+itertools = "0.13.0"
line-index = { path = "../line-index" }
-log = "0.4.21"
+log = "0.4.22"
multimap = "0.10.0"
once_cell = "1.19.0"
-regex = "1.10.4"
+regex = "1.10.5"
rowan = "0.15.15"
-rustc-hash = "1.1.0"
+rustc-hash = "2.0.0"
syntax = { path = "../syntax" }
url = "2.5.0"
diff --git a/support/texlab/crates/distro/Cargo.toml b/support/texlab/crates/distro/Cargo.toml
index dea6a56979..c81288e86e 100644
--- a/support/texlab/crates/distro/Cargo.toml
+++ b/support/texlab/crates/distro/Cargo.toml
@@ -8,7 +8,7 @@ rust-version.workspace = true
[dependencies]
anyhow = "1.0.86"
-rustc-hash = "1.1.0"
+rustc-hash = "2.0.0"
[lib]
doctest = false
diff --git a/support/texlab/crates/distro/src/language.rs b/support/texlab/crates/distro/src/language.rs
index 201ed0702b..0a94a93604 100644
--- a/support/texlab/crates/distro/src/language.rs
+++ b/support/texlab/crates/distro/src/language.rs
@@ -9,6 +9,7 @@ pub enum Language {
Root,
Latexmkrc,
Tectonic,
+ FileList,
}
impl Language {
@@ -32,6 +33,7 @@ impl Language {
"bib" | "bibtex" => Some(Self::Bib),
"aux" => Some(Self::Aux),
"log" => Some(Self::Log),
+ "fls" => Some(Self::FileList),
_ => None,
}
}
diff --git a/support/texlab/crates/inlay-hints/Cargo.toml b/support/texlab/crates/inlay-hints/Cargo.toml
index ede4ca6188..94651ef4c7 100644
--- a/support/texlab/crates/inlay-hints/Cargo.toml
+++ b/support/texlab/crates/inlay-hints/Cargo.toml
@@ -9,7 +9,7 @@ rust-version.workspace = true
[dependencies]
base-db = { path = "../base-db" }
rowan = "0.15.15"
-rustc-hash = "1.1.0"
+rustc-hash = "2.0.0"
[dev-dependencies]
test-utils = { path = "../test-utils" }
diff --git a/support/texlab/crates/ipc/Cargo.toml b/support/texlab/crates/ipc/Cargo.toml
index 1e1ff7a822..92afbba876 100644
--- a/support/texlab/crates/ipc/Cargo.toml
+++ b/support/texlab/crates/ipc/Cargo.toml
@@ -7,10 +7,10 @@ edition.workspace = true
rust-version.workspace = true
[dependencies]
-crossbeam-channel = "0.5.12"
-serde = "1.0.202"
-serde_json = "1.0.117"
-log = "0.4.21"
+crossbeam-channel = "0.5.13"
+serde = "1.0.203"
+serde_json = "1.0.119"
+log = "0.4.22"
uds_windows = "1.1.0"
[lib]
diff --git a/support/texlab/crates/line-index/Cargo.toml b/support/texlab/crates/line-index/Cargo.toml
index 73d2766d60..58e2fa9e16 100644
--- a/support/texlab/crates/line-index/Cargo.toml
+++ b/support/texlab/crates/line-index/Cargo.toml
@@ -7,7 +7,7 @@ edition.workspace = true
rust-version.workspace = true
[dependencies]
-rustc-hash = "1.1.0"
+rustc-hash = "2.0.0"
text-size = "1.1.1"
[lib]
diff --git a/support/texlab/crates/parser/Cargo.toml b/support/texlab/crates/parser/Cargo.toml
index 39fa34ef63..2faadcb262 100644
--- a/support/texlab/crates/parser/Cargo.toml
+++ b/support/texlab/crates/parser/Cargo.toml
@@ -7,16 +7,16 @@ edition.workspace = true
rust-version.workspace = true
[dependencies]
-log = "0.4.21"
+log = "0.4.22"
logos = "0.14.0"
once_cell = "1.19.0"
pathdiff = "0.2.1"
-regex = "1.10.4"
+regex = "1.10.5"
rowan = "0.15.15"
-rustc-hash = "1.1.0"
+rustc-hash = "2.0.0"
syntax = { path = "../syntax" }
tempfile = "3.10.1"
-versions = "6.2.0"
+versions = "6.3.0"
[dev-dependencies]
expect-test = "1.5.0"
diff --git a/support/texlab/crates/parser/src/bibtex.rs b/support/texlab/crates/parser/src/bibtex.rs
index e2cde27dec..4d1e561dbe 100644
--- a/support/texlab/crates/parser/src/bibtex.rs
+++ b/support/texlab/crates/parser/src/bibtex.rs
@@ -2,6 +2,8 @@ use logos::Logos;
use rowan::{GreenNode, GreenNodeBuilder};
use syntax::bibtex::SyntaxKind::{self, *};
+use crate::util::lex_command_name;
+
pub fn parse_bibtex(input: &str) -> GreenNode {
let mut ptr = TokenPtr {
builder: GreenNodeBuilder::new(),
@@ -135,8 +137,8 @@ fn curly_group(mut ptr: TokenPtr<ContentToken>) -> TokenPtr<ContentToken> {
| ContentToken::Quote
| ContentToken::Word => ptr.bump(),
ContentToken::LCurly => ptr = curly_group(ptr),
- ContentToken::AccentName => ptr = accent(ptr),
- ContentToken::CommandName => ptr = command(ptr),
+ ContentToken::CommandName(CommandName::Accent) => ptr = accent(ptr),
+ ContentToken::CommandName(CommandName::Generic) => ptr = command(ptr),
};
}
@@ -160,8 +162,8 @@ fn quote_group(mut ptr: TokenPtr<ContentToken>) -> TokenPtr<ContentToken> {
| ContentToken::Integer
| ContentToken::Word => ptr.bump(),
ContentToken::LCurly => ptr = curly_group(ptr),
- ContentToken::AccentName => ptr = accent(ptr),
- ContentToken::CommandName => ptr = command(ptr),
+ ContentToken::CommandName(CommandName::Accent) => ptr = accent(ptr),
+ ContentToken::CommandName(CommandName::Generic) => ptr = command(ptr),
};
}
@@ -181,7 +183,7 @@ fn accent(mut ptr: TokenPtr<ContentToken>) -> TokenPtr<ContentToken> {
ptr.expect(ContentToken::Whitespace);
}
- if ptr.at(ContentToken::Word) || ptr.at(ContentToken::CommandName) {
+ if ptr.at(ContentToken::Word) || ptr.at(ContentToken::CommandName(CommandName::Generic)) {
ptr.bump();
}
@@ -355,31 +357,29 @@ enum ContentToken {
#[token(r#"~"#)]
Nbsp,
- #[token(r#"\`"#)]
- #[token(r#"\'"#)]
- #[token(r#"\^"#)]
- #[token(r#"\""#)]
- #[token(r#"\H"#)]
- #[token(r#"\~"#)]
- #[token(r#"\c"#)]
- #[token(r#"\k"#)]
- #[token(r#"\="#)]
- #[token(r#"\b"#)]
- #[token(r#"\."#)]
- #[token(r#"\d"#)]
- #[token(r#"\r"#)]
- #[token(r#"\u"#)]
- #[token(r#"\v"#)]
- #[token(r#"\t"#)]
- AccentName,
-
- #[regex(r"\\([^\r\n]|[@a-zA-Z:_]+\*?)?")]
- CommandName,
+ #[regex(r"\\", |lexer| { CommandName::from(lex_command_name(lexer)) })]
+ CommandName(CommandName),
#[regex(r#"[^\s"\{\}\\~,]+"#)]
Word,
}
+#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash)]
+enum CommandName {
+ Generic,
+ Accent,
+}
+
+impl From<&str> for CommandName {
+ fn from(value: &str) -> Self {
+ match value {
+ "`" | "'" | "^" | "\"" | "H" | "~" | "c" | "k" | "=" | "b" | "." | "d" | "r" | "u"
+ | "v" | "t" => CommandName::Accent,
+ _ => CommandName::Generic,
+ }
+ }
+}
+
impl From<RootToken> for SyntaxKind {
fn from(token: RootToken) -> Self {
match token {
@@ -428,8 +428,8 @@ impl From<ContentToken> for SyntaxKind {
ContentToken::Quote => QUOTE,
ContentToken::Integer => INTEGER,
ContentToken::Nbsp => NBSP,
- ContentToken::AccentName => ACCENT_NAME,
- ContentToken::CommandName => COMMAND_NAME,
+ ContentToken::CommandName(CommandName::Accent) => ACCENT_NAME,
+ ContentToken::CommandName(CommandName::Generic) => COMMAND_NAME,
ContentToken::Word => WORD,
}
}
diff --git a/support/texlab/crates/parser/src/bibtex/tests.rs b/support/texlab/crates/parser/src/bibtex/tests.rs
index e2bb1314d8..f0872b4ca6 100644
--- a/support/texlab/crates/parser/src/bibtex/tests.rs
+++ b/support/texlab/crates/parser/src/bibtex/tests.rs
@@ -3992,3 +3992,280 @@ fn test_rivest_1978() {
"#]],
);
}
+
+#[test]
+fn test_cuesta_2002() {
+ check(
+ r#"@INPROCEEDINGS{Cuesta02,
+ author = {Cuesta, Carlos E. and de la Fuente, Pablo and Barrio-Sol\órzano, Manuel and Beato, Encarnaci\ón},
+ title = {{Coordination in a Reflective Architecture Description Language}},
+ booktitle = {{Proceedings of the 5th International Conference on Coordination Models and Languages (COORDINATION'02)}},
+ year = 2002,
+ editor = {Arbab, Fahrad and Talcott, Carolyn},
+ pages = {141--148},
+ address = {York, United Kingdom},
+ organization = {},
+ publisher = {Springer},
+ volume = {},
+ number = {},
+ series = {Lecture Notes in Computer Science 2315},
+ month = apr,
+ note = {}
+}"#,
+ expect![[r#"
+ ROOT@0..617
+ ENTRY@0..617
+ TYPE@0..14 "@INPROCEEDINGS"
+ L_DELIM@14..15 "{"
+ NAME@15..23 "Cuesta02"
+ COMMA@23..24 ","
+ WHITESPACE@24..27 "\n "
+ FIELD@27..136
+ NAME@27..33 "author"
+ WHITESPACE@33..34 " "
+ EQ@34..35 "="
+ WHITESPACE@35..36 " "
+ CURLY_GROUP@36..135
+ L_CURLY@36..37 "{"
+ WORD@37..43 "Cuesta"
+ COMMA@43..44 ","
+ WHITESPACE@44..45 " "
+ WORD@45..51 "Carlos"
+ WHITESPACE@51..52 " "
+ WORD@52..54 "E."
+ WHITESPACE@54..55 " "
+ WORD@55..58 "and"
+ WHITESPACE@58..59 " "
+ WORD@59..61 "de"
+ WHITESPACE@61..62 " "
+ WORD@62..64 "la"
+ WHITESPACE@64..65 " "
+ WORD@65..71 "Fuente"
+ COMMA@71..72 ","
+ WHITESPACE@72..73 " "
+ WORD@73..78 "Pablo"
+ WHITESPACE@78..79 " "
+ WORD@79..82 "and"
+ WHITESPACE@82..83 " "
+ WORD@83..93 "Barrio-Sol"
+ COMMAND@93..101
+ COMMAND_NAME@93..101 "\\órzano"
+ COMMA@101..102 ","
+ WHITESPACE@102..103 " "
+ WORD@103..109 "Manuel"
+ WHITESPACE@109..110 " "
+ WORD@110..113 "and"
+ WHITESPACE@113..114 " "
+ WORD@114..119 "Beato"
+ COMMA@119..120 ","
+ WHITESPACE@120..121 " "
+ WORD@121..130 "Encarnaci"
+ COMMAND@130..134
+ COMMAND_NAME@130..134 "\\ón"
+ R_CURLY@134..135 "}"
+ COMMA@135..136 ","
+ WHITESPACE@136..139 "\n "
+ FIELD@139..214
+ NAME@139..144 "title"
+ WHITESPACE@144..145 " "
+ EQ@145..146 "="
+ WHITESPACE@146..147 " "
+ CURLY_GROUP@147..213
+ L_CURLY@147..148 "{"
+ CURLY_GROUP@148..212
+ L_CURLY@148..149 "{"
+ WORD@149..161 "Coordination"
+ WHITESPACE@161..162 " "
+ WORD@162..164 "in"
+ WHITESPACE@164..165 " "
+ WORD@165..166 "a"
+ WHITESPACE@166..167 " "
+ WORD@167..177 "Reflective"
+ WHITESPACE@177..178 " "
+ WORD@178..190 "Architecture"
+ WHITESPACE@190..191 " "
+ WORD@191..202 "Description"
+ WHITESPACE@202..203 " "
+ WORD@203..211 "Language"
+ R_CURLY@211..212 "}"
+ R_CURLY@212..213 "}"
+ COMMA@213..214 ","
+ WHITESPACE@214..217 "\n "
+ FIELD@217..336
+ NAME@217..226 "booktitle"
+ WHITESPACE@226..227 " "
+ EQ@227..228 "="
+ WHITESPACE@228..229 " "
+ CURLY_GROUP@229..335
+ L_CURLY@229..230 "{"
+ CURLY_GROUP@230..334
+ L_CURLY@230..231 "{"
+ WORD@231..242 "Proceedings"
+ WHITESPACE@242..243 " "
+ WORD@243..245 "of"
+ WHITESPACE@245..246 " "
+ WORD@246..249 "the"
+ WHITESPACE@249..250 " "
+ WORD@250..253 "5th"
+ WHITESPACE@253..254 " "
+ WORD@254..267 "International"
+ WHITESPACE@267..268 " "
+ WORD@268..278 "Conference"
+ WHITESPACE@278..279 " "
+ WORD@279..281 "on"
+ WHITESPACE@281..282 " "
+ WORD@282..294 "Coordination"
+ WHITESPACE@294..295 " "
+ WORD@295..301 "Models"
+ WHITESPACE@301..302 " "
+ WORD@302..305 "and"
+ WHITESPACE@305..306 " "
+ WORD@306..315 "Languages"
+ WHITESPACE@315..316 " "
+ WORD@316..333 "(COORDINATION'02)"
+ R_CURLY@333..334 "}"
+ R_CURLY@334..335 "}"
+ COMMA@335..336 ","
+ WHITESPACE@336..339 "\n "
+ FIELD@339..351
+ NAME@339..343 "year"
+ WHITESPACE@343..344 " "
+ EQ@344..345 "="
+ WHITESPACE@345..346 " "
+ LITERAL@346..350
+ INTEGER@346..350 "2002"
+ COMMA@350..351 ","
+ WHITESPACE@351..354 "\n "
+ FIELD@354..400
+ NAME@354..360 "editor"
+ WHITESPACE@360..361 " "
+ EQ@361..362 "="
+ WHITESPACE@362..363 " "
+ CURLY_GROUP@363..399
+ L_CURLY@363..364 "{"
+ WORD@364..369 "Arbab"
+ COMMA@369..370 ","
+ WHITESPACE@370..371 " "
+ WORD@371..377 "Fahrad"
+ WHITESPACE@377..378 " "
+ WORD@378..381 "and"
+ WHITESPACE@381..382 " "
+ WORD@382..389 "Talcott"
+ COMMA@389..390 ","
+ WHITESPACE@390..391 " "
+ WORD@391..398 "Carolyn"
+ R_CURLY@398..399 "}"
+ COMMA@399..400 ","
+ WHITESPACE@400..403 "\n "
+ FIELD@403..422
+ NAME@403..408 "pages"
+ WHITESPACE@408..409 " "
+ EQ@409..410 "="
+ WHITESPACE@410..411 " "
+ CURLY_GROUP@411..421
+ L_CURLY@411..412 "{"
+ WORD@412..420 "141--148"
+ R_CURLY@420..421 "}"
+ COMMA@421..422 ","
+ WHITESPACE@422..425 "\n "
+ FIELD@425..458
+ NAME@425..432 "address"
+ WHITESPACE@432..433 " "
+ EQ@433..434 "="
+ WHITESPACE@434..435 " "
+ CURLY_GROUP@435..457
+ L_CURLY@435..436 "{"
+ WORD@436..440 "York"
+ COMMA@440..441 ","
+ WHITESPACE@441..442 " "
+ WORD@442..448 "United"
+ WHITESPACE@448..449 " "
+ WORD@449..456 "Kingdom"
+ R_CURLY@456..457 "}"
+ COMMA@457..458 ","
+ WHITESPACE@458..461 "\n "
+ FIELD@461..479
+ NAME@461..473 "organization"
+ WHITESPACE@473..474 " "
+ EQ@474..475 "="
+ WHITESPACE@475..476 " "
+ CURLY_GROUP@476..478
+ L_CURLY@476..477 "{"
+ R_CURLY@477..478 "}"
+ COMMA@478..479 ","
+ WHITESPACE@479..482 "\n "
+ FIELD@482..505
+ NAME@482..491 "publisher"
+ WHITESPACE@491..492 " "
+ EQ@492..493 "="
+ WHITESPACE@493..494 " "
+ CURLY_GROUP@494..504
+ L_CURLY@494..495 "{"
+ WORD@495..503 "Springer"
+ R_CURLY@503..504 "}"
+ COMMA@504..505 ","
+ WHITESPACE@505..508 "\n "
+ FIELD@508..520
+ NAME@508..514 "volume"
+ WHITESPACE@514..515 " "
+ EQ@515..516 "="
+ WHITESPACE@516..517 " "
+ CURLY_GROUP@517..519
+ L_CURLY@517..518 "{"
+ R_CURLY@518..519 "}"
+ COMMA@519..520 ","
+ WHITESPACE@520..523 "\n "
+ FIELD@523..535
+ NAME@523..529 "number"
+ WHITESPACE@529..530 " "
+ EQ@530..531 "="
+ WHITESPACE@531..532 " "
+ CURLY_GROUP@532..534
+ L_CURLY@532..533 "{"
+ R_CURLY@533..534 "}"
+ COMMA@534..535 ","
+ WHITESPACE@535..538 "\n "
+ FIELD@538..588
+ NAME@538..544 "series"
+ WHITESPACE@544..545 " "
+ EQ@545..546 "="
+ WHITESPACE@546..547 " "
+ CURLY_GROUP@547..587
+ L_CURLY@547..548 "{"
+ WORD@548..555 "Lecture"
+ WHITESPACE@555..556 " "
+ WORD@556..561 "Notes"
+ WHITESPACE@561..562 " "
+ WORD@562..564 "in"
+ WHITESPACE@564..565 " "
+ WORD@565..573 "Computer"
+ WHITESPACE@573..574 " "
+ WORD@574..581 "Science"
+ WHITESPACE@581..582 " "
+ INTEGER@582..586 "2315"
+ R_CURLY@586..587 "}"
+ COMMA@587..588 ","
+ WHITESPACE@588..591 "\n "
+ FIELD@591..603
+ NAME@591..596 "month"
+ WHITESPACE@596..597 " "
+ EQ@597..598 "="
+ WHITESPACE@598..599 " "
+ LITERAL@599..602
+ NAME@599..602 "apr"
+ COMMA@602..603 ","
+ WHITESPACE@603..606 "\n "
+ FIELD@606..616
+ NAME@606..610 "note"
+ WHITESPACE@610..611 " "
+ EQ@611..612 "="
+ WHITESPACE@612..613 " "
+ CURLY_GROUP@613..615
+ L_CURLY@613..614 "{"
+ R_CURLY@614..615 "}"
+ WHITESPACE@615..616 "\n"
+ R_DELIM@616..617 "}"
+
+ "#]],
+ )
+}
diff --git a/support/texlab/crates/parser/src/file_list.rs b/support/texlab/crates/parser/src/file_list.rs
new file mode 100644
index 0000000000..c892ebfeef
--- /dev/null
+++ b/support/texlab/crates/parser/src/file_list.rs
@@ -0,0 +1,44 @@
+use syntax::file_list::FileList;
+
+pub fn parse_file_list(input: &str) -> FileList {
+ let mut file_list = FileList::default();
+ for line in input.lines() {
+ if let Some(working_dir) = line.strip_prefix("PWD ") {
+ file_list.working_dir = Some(working_dir.into());
+ } else if let Some(input) = line.strip_prefix("INPUT ") {
+ file_list.inputs.insert(input.into());
+ } else if let Some(output) = line.strip_prefix("OUTPUT ") {
+ file_list.outputs.insert(output.into());
+ }
+ }
+
+ file_list
+}
+
+#[cfg(test)]
+mod tests {
+ use rustc_hash::FxHashSet;
+
+ use super::*;
+
+ #[test]
+ fn test_parse_file_list() {
+ let input = r#"
+PWD /home/user
+INPUT file1.tex
+INPUT file1.tex
+OUTPUT file2.pdf"#;
+
+ let expected_file_list = FileList {
+ working_dir: Some("/home/user".into()),
+ inputs: FxHashSet::from_iter(["file1.tex".into()]),
+ outputs: FxHashSet::from_iter(["file2.pdf".into()]),
+ };
+ let actual_file_list = parse_file_list(input);
+ assert_eq!(actual_file_list, expected_file_list);
+
+ assert_eq!(actual_file_list.working_dir, Some("/home/user".into()));
+ assert_eq!(actual_file_list.inputs.len(), 1);
+ assert_eq!(actual_file_list.outputs.len(), 1);
+ }
+}
diff --git a/support/texlab/crates/parser/src/latex/lexer/types.rs b/support/texlab/crates/parser/src/latex/lexer/types.rs
index 896ce01c05..85e542792b 100644
--- a/support/texlab/crates/parser/src/latex/lexer/types.rs
+++ b/support/texlab/crates/parser/src/latex/lexer/types.rs
@@ -1,5 +1,7 @@
use logos::Logos;
+use crate::util::lex_command_name;
+
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash, Logos)]
pub enum Token {
#[regex(r"[\r\n]+", priority = 2)]
@@ -44,55 +46,10 @@ pub enum Token {
#[regex(r"\$\$?")]
Dollar,
- #[regex(r"\\", lex_command_name)]
+ #[regex(r"\\", |lexer| { lex_command_name(lexer); CommandName::Generic } )]
CommandName(CommandName),
}
-fn lex_command_name(lexer: &mut logos::Lexer<Token>) -> CommandName {
- let input = &lexer.source()[lexer.span().end..];
-
- let mut chars = input.chars().peekable();
- let Some(c) = chars.next() else {
- return CommandName::Generic;
- };
-
- if c.is_whitespace() {
- return CommandName::Generic;
- }
-
- lexer.bump(c.len_utf8());
- if !c.is_alphanumeric() && c != '@' {
- return CommandName::Generic;
- }
-
- while let Some(c) = chars.next() {
- match c {
- '*' => {
- lexer.bump(c.len_utf8());
- break;
- }
- c if c.is_alphanumeric() => {
- lexer.bump(c.len_utf8());
- }
- '_' => {
- if !matches!(chars.peek(), Some(c) if c.is_alphanumeric()) {
- break;
- }
-
- lexer.bump(c.len_utf8());
- }
- '@' | ':' => {
- lexer.bump(c.len_utf8());
- }
- _ => {
- break;
- }
- }
- }
-
- CommandName::Generic
-}
-
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash)]
pub enum CommandName {
Generic,
diff --git a/support/texlab/crates/parser/src/lib.rs b/support/texlab/crates/parser/src/lib.rs
index 2a4190b7e2..b3952d6ea5 100644
--- a/support/texlab/crates/parser/src/lib.rs
+++ b/support/texlab/crates/parser/src/lib.rs
@@ -1,10 +1,12 @@
mod bibtex;
mod build_log;
mod config;
+mod file_list;
mod latex;
mod latexmkrc;
+pub(crate) mod util;
pub use self::{
- bibtex::parse_bibtex, build_log::parse_build_log, config::*, latex::parse_latex,
- latexmkrc::parse_latexmkrc,
+ bibtex::parse_bibtex, build_log::parse_build_log, config::*, file_list::parse_file_list,
+ latex::parse_latex, latexmkrc::parse_latexmkrc,
};
diff --git a/support/texlab/crates/parser/src/util.rs b/support/texlab/crates/parser/src/util.rs
new file mode 100644
index 0000000000..cb147c493b
--- /dev/null
+++ b/support/texlab/crates/parser/src/util.rs
@@ -0,0 +1,52 @@
+use std::ops::{Index, Range};
+
+use logos::{Logos, Source};
+
+pub fn lex_command_name<'a, T>(lexer: &mut logos::Lexer<'a, T>) -> &'a str
+where
+ T: Logos<'a>,
+ T::Source: Index<Range<usize>, Output = str>,
+{
+ let start = lexer.span().end;
+ let input = &lexer.source()[start..lexer.source().len()];
+
+ let mut chars = input.chars().peekable();
+ let Some(c) = chars.next() else {
+ return "";
+ };
+
+ if c.is_whitespace() {
+ return "";
+ }
+
+ lexer.bump(c.len_utf8());
+
+ if c.is_alphanumeric() || c == '@' {
+ while let Some(c) = chars.next() {
+ match c {
+ '*' => {
+ lexer.bump(c.len_utf8());
+ break;
+ }
+ c if c.is_alphanumeric() => {
+ lexer.bump(c.len_utf8());
+ }
+ '_' => {
+ if !matches!(chars.peek(), Some(c) if c.is_alphanumeric()) {
+ break;
+ }
+
+ lexer.bump(c.len_utf8());
+ }
+ '@' | ':' => {
+ lexer.bump(c.len_utf8());
+ }
+ _ => {
+ break;
+ }
+ }
+ }
+ }
+
+ &lexer.source()[start..lexer.span().end]
+}
diff --git a/support/texlab/crates/references/Cargo.toml b/support/texlab/crates/references/Cargo.toml
index e78e84ea4c..8d4e3a6936 100644
--- a/support/texlab/crates/references/Cargo.toml
+++ b/support/texlab/crates/references/Cargo.toml
@@ -9,7 +9,7 @@ rust-version.workspace = true
[dependencies]
base-db = { path = "../base-db" }
rowan = "0.15.15"
-rustc-hash = "1.1.0"
+rustc-hash = "2.0.0"
syntax = { path = "../syntax" }
[dev-dependencies]
diff --git a/support/texlab/crates/rename/Cargo.toml b/support/texlab/crates/rename/Cargo.toml
index dc7558515a..592bafb474 100644
--- a/support/texlab/crates/rename/Cargo.toml
+++ b/support/texlab/crates/rename/Cargo.toml
@@ -9,7 +9,7 @@ rust-version.workspace = true
[dependencies]
base-db = { path = "../base-db" }
rowan = "0.15.15"
-rustc-hash = "1.1.0"
+rustc-hash = "2.0.0"
syntax = { path = "../syntax" }
[dev-dependencies]
diff --git a/support/texlab/crates/symbols/Cargo.toml b/support/texlab/crates/symbols/Cargo.toml
index 65db0fc0bd..c44f120153 100644
--- a/support/texlab/crates/symbols/Cargo.toml
+++ b/support/texlab/crates/symbols/Cargo.toml
@@ -12,7 +12,7 @@ doctest = false
[dependencies]
base-db = { path = "../base-db" }
distro = { path = "../distro" }
-itertools = "0.12.1"
+itertools = "0.13.0"
line-index = { path = "../line-index" }
rowan = "0.15.15"
syntax = { path = "../syntax" }
@@ -20,6 +20,6 @@ titlecase = "3.0.0"
url = "2.5.0"
[dev-dependencies]
-regex = "1.10.4"
+regex = "1.10.5"
test-utils = { path = "../test-utils" }
expect-test = "1.5.0"
diff --git a/support/texlab/crates/symbols/src/document.rs b/support/texlab/crates/symbols/src/document.rs
index 791f119919..611a7e0370 100644
--- a/support/texlab/crates/symbols/src/document.rs
+++ b/support/texlab/crates/symbols/src/document.rs
@@ -23,6 +23,7 @@ pub fn document_symbols(workspace: &Workspace, document: &Document) -> Vec<Symbo
| DocumentData::Log(_)
| DocumentData::Root
| DocumentData::Latexmkrc(_)
+ | DocumentData::FileList(_)
| DocumentData::Tectonic => Vec::new(),
};
diff --git a/support/texlab/crates/syntax/Cargo.toml b/support/texlab/crates/syntax/Cargo.toml
index a2d3d866b6..14dfffe380 100644
--- a/support/texlab/crates/syntax/Cargo.toml
+++ b/support/texlab/crates/syntax/Cargo.toml
@@ -7,8 +7,9 @@ edition.workspace = true
rust-version.workspace = true
[dependencies]
-itertools = "0.12.1"
+itertools = "0.13.0"
rowan = "0.15.15"
+rustc-hash = "2.0.0"
[lib]
doctest = false
diff --git a/support/texlab/crates/syntax/src/file_list.rs b/support/texlab/crates/syntax/src/file_list.rs
new file mode 100644
index 0000000000..cd32e787da
--- /dev/null
+++ b/support/texlab/crates/syntax/src/file_list.rs
@@ -0,0 +1,10 @@
+use std::path::PathBuf;
+
+use rustc_hash::FxHashSet;
+
+#[derive(Debug, PartialEq, Eq, Clone, Default)]
+pub struct FileList {
+ pub working_dir: Option<PathBuf>,
+ pub inputs: FxHashSet<PathBuf>,
+ pub outputs: FxHashSet<PathBuf>,
+}
diff --git a/support/texlab/crates/syntax/src/lib.rs b/support/texlab/crates/syntax/src/lib.rs
index 35f1bb8c52..d3e2098757 100644
--- a/support/texlab/crates/syntax/src/lib.rs
+++ b/support/texlab/crates/syntax/src/lib.rs
@@ -1,4 +1,5 @@
pub mod bibtex;
+pub mod file_list;
pub mod latex;
pub mod latexmkrc;
diff --git a/support/texlab/crates/texlab/Cargo.toml b/support/texlab/crates/texlab/Cargo.toml
index fa419413f5..c6fca1bfda 100644
--- a/support/texlab/crates/texlab/Cargo.toml
+++ b/support/texlab/crates/texlab/Cargo.toml
@@ -1,7 +1,7 @@
[package]
name = "texlab"
description = "LaTeX Language Server"
-version = "5.17.0"
+version = "5.18.0"
license.workspace = true
readme = "README.md"
authors.workspace = true
@@ -26,11 +26,11 @@ anyhow = "1.0.86"
base-db = { path = "../base-db" }
bibfmt = { path = "../bibfmt" }
citeproc = { path = "../citeproc" }
-clap = { version = "4.5.4", features = ["derive"] }
+clap = { version = "4.5.8", features = ["derive"] }
commands = { path = "../commands" }
completion = { path = "../completion" }
completion-data = { path = "../completion-data" }
-crossbeam-channel = "0.5.12"
+crossbeam-channel = "0.5.13"
definition = { path = "../definition" }
diagnostics = { path = "../diagnostics" }
distro = { path = "../distro" }
@@ -42,7 +42,7 @@ inlay-hints = { path = "../inlay-hints" }
ipc = { path = "../ipc" }
line-index = { path = "../line-index" }
links = { path = "../links" }
-log = "0.4.21"
+log = "0.4.22"
lsp-server = "0.7.6"
lsp-types = "0.95.1"
notify = "6.1.1"
@@ -50,12 +50,12 @@ notify-debouncer-full = "0.3.1"
parking_lot = "0.12.3"
parser = { path = "../parser" }
references = { path = "../references" }
-regex = "1.10.4"
+regex = "1.10.5"
rename = { path = "../rename" }
rowan = "0.15.15"
-rustc-hash = "1.1.0"
-serde = "1.0.202"
-serde_json = "1.0.117"
+rustc-hash = "2.0.0"
+serde = "1.0.203"
+serde_json = "1.0.119"
serde_regex = "1.1.0"
serde_repr = "0.1.19"
symbols = { path = "../symbols" }
diff --git a/support/texlab/crates/texlab/src/features/formatting.rs b/support/texlab/crates/texlab/src/features/formatting.rs
index 3fcd66e39b..9d152f6e8b 100644
--- a/support/texlab/crates/texlab/src/features/formatting.rs
+++ b/support/texlab/crates/texlab/src/features/formatting.rs
@@ -27,6 +27,7 @@ pub fn format_source_code(
| Language::Log
| Language::Root
| Language::Latexmkrc
- | Language::Tectonic => None,
+ | Language::Tectonic
+ | Language::FileList => None,
}
}
diff --git a/support/texlab/crates/texlab/src/util.rs b/support/texlab/crates/texlab/src/util.rs
index c301dc7722..87e41a78ae 100644
--- a/support/texlab/crates/texlab/src/util.rs
+++ b/support/texlab/crates/texlab/src/util.rs
@@ -18,9 +18,28 @@ pub fn normalize_uri(uri: &mut lsp_types::Url) {
}
}
+ uri.set_path(&normalize_percent_encoding(uri.path()));
uri.set_fragment(None);
}
+fn normalize_percent_encoding(input: &str) -> String {
+ let mut output = String::new();
+ let mut i = 0;
+ for c in input.chars() {
+ if c == '%' && i == 0 {
+ output.push(c);
+ i = 2;
+ } else if i > 0 {
+ output.push(c.to_ascii_uppercase());
+ i -= 1;
+ } else {
+ output.push(c);
+ }
+ }
+
+ output
+}
+
fn fix_drive_letter(text: &str) -> Option<String> {
if !text.is_ascii() || text.is_empty() {
return None;
@@ -59,4 +78,44 @@ mod tests {
normalize_uri(&mut uri);
assert_eq!(uri.as_str(), "foo:///bar/baz.txt");
}
+
+ #[test]
+ #[cfg(unix)]
+ fn test_lowercase_percent_encoding_unix() {
+ let mut uri1 = Url::parse("file:///foo/%c3%a4.tex").unwrap();
+ let uri2 = Url::from_file_path("/foo/ä.tex").unwrap();
+
+ normalize_uri(&mut uri1);
+ assert_eq!(uri1, uri2);
+ }
+
+ #[test]
+ #[cfg(unix)]
+ fn test_uppercase_percent_encoding_unix() {
+ let mut uri1 = Url::parse("file:///foo/%C3%A4.tex").unwrap();
+ let uri2 = Url::from_file_path("/foo/ä.tex").unwrap();
+
+ normalize_uri(&mut uri1);
+ assert_eq!(uri1, uri2);
+ }
+
+ #[test]
+ #[cfg(windows)]
+ fn test_lowercase_percent_encoding_windows() {
+ let mut uri1 = Url::parse("file:///c%3a/foo/%c3%a4.tex").unwrap();
+ let uri2 = Url::from_file_path("C:/foo/ä.tex").unwrap();
+
+ normalize_uri(&mut uri1);
+ assert_eq!(uri1, uri2);
+ }
+
+ #[test]
+ #[cfg(windows)]
+ fn test_uppercase_percent_encoding_windows() {
+ let mut uri1 = Url::parse("file:///c%3A/foo/%C3%A4.tex").unwrap();
+ let uri2 = Url::from_file_path("C:/foo/ä.tex").unwrap();
+
+ normalize_uri(&mut uri1);
+ assert_eq!(uri1, uri2);
+ }
}