mirror of
https://github.com/latex-lsp/texlab.git
synced 2025-08-04 02:39:21 +00:00
Refactor workspace commands
This commit is contained in:
parent
9d1f57891d
commit
418ba1907e
17 changed files with 293 additions and 269 deletions
21
crates/commands/Cargo.toml
Normal file
21
crates/commands/Cargo.toml
Normal file
|
@ -0,0 +1,21 @@
|
|||
[package]
|
||||
name = "commands"
|
||||
version = "0.0.0"
|
||||
license.workspace = true
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
rust-version.workspace = true
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0.70"
|
||||
base-db = { path = "../base-db" }
|
||||
base-feature = { path = "../base-feature" }
|
||||
itertools = "0.10.5"
|
||||
log = "0.4.17"
|
||||
rowan = "0.15.11"
|
||||
rustc-hash = "1.1.0"
|
||||
syntax = { path = "../syntax" }
|
||||
url = "2.3.1"
|
||||
|
||||
[lib]
|
||||
doctest = false
|
40
crates/commands/src/change_env.rs
Normal file
40
crates/commands/src/change_env.rs
Normal file
|
@ -0,0 +1,40 @@
|
|||
use base_db::Document;
|
||||
use rowan::{ast::AstNode, TextRange, TextSize};
|
||||
use syntax::latex;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ChangeEnvironmentResult<'a> {
|
||||
pub begin: TextRange,
|
||||
pub end: TextRange,
|
||||
pub old_name: String,
|
||||
pub new_name: &'a str,
|
||||
}
|
||||
|
||||
pub fn change_environment<'a>(
|
||||
document: &'a Document,
|
||||
position: TextSize,
|
||||
new_name: &'a str,
|
||||
) -> Option<ChangeEnvironmentResult<'a>> {
|
||||
let root = document.data.as_tex()?.root_node();
|
||||
|
||||
let environment = root
|
||||
.token_at_offset(position)
|
||||
.right_biased()?
|
||||
.parent_ancestors()
|
||||
.find_map(latex::Environment::cast)?;
|
||||
|
||||
let begin = environment.begin()?.name()?.key()?;
|
||||
let end = environment.end()?.name()?.key()?;
|
||||
|
||||
let old_name = begin.to_string();
|
||||
if old_name != end.to_string() {
|
||||
return None;
|
||||
}
|
||||
|
||||
Some(ChangeEnvironmentResult {
|
||||
begin: latex::small_range(&begin),
|
||||
end: latex::small_range(&end),
|
||||
old_name,
|
||||
new_name,
|
||||
})
|
||||
}
|
57
crates/commands/src/clean.rs
Normal file
57
crates/commands/src/clean.rs
Normal file
|
@ -0,0 +1,57 @@
|
|||
use std::process::Stdio;
|
||||
|
||||
use anyhow::Result;
|
||||
use base_db::{Document, Workspace};
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash)]
|
||||
pub enum CleanTarget {
|
||||
Auxiliary,
|
||||
Artifacts,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct CleanCommand {
|
||||
executable: String,
|
||||
args: Vec<String>,
|
||||
}
|
||||
|
||||
impl CleanCommand {
|
||||
pub fn new(workspace: &Workspace, document: &Document, target: CleanTarget) -> Result<Self> {
|
||||
let Some(path) = document.path.as_deref() else {
|
||||
anyhow::bail!("document '{}' is not a local file", document.uri)
|
||||
};
|
||||
|
||||
let dir = workspace.current_dir(&document.dir);
|
||||
let dir = workspace.output_dir(&dir).to_file_path().unwrap();
|
||||
|
||||
let flag = match target {
|
||||
CleanTarget::Auxiliary => "-c",
|
||||
CleanTarget::Artifacts => "-C",
|
||||
};
|
||||
|
||||
let executable = String::from("latexmk");
|
||||
let args = vec![
|
||||
format!("-outdir={}", dir.display()),
|
||||
String::from(flag),
|
||||
path.display().to_string(),
|
||||
];
|
||||
|
||||
Ok(Self { executable, args })
|
||||
}
|
||||
|
||||
pub fn run(self) -> Result<()> {
|
||||
log::debug!("Cleaning output files: {} {:?}", self.executable, self.args);
|
||||
let result = std::process::Command::new(self.executable)
|
||||
.args(self.args)
|
||||
.stdin(Stdio::null())
|
||||
.stdout(Stdio::null())
|
||||
.stderr(Stdio::null())
|
||||
.status();
|
||||
|
||||
if let Err(why) = result {
|
||||
anyhow::bail!("failed to spawn process: {why}")
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
57
crates/commands/src/dep_graph.rs
Normal file
57
crates/commands/src/dep_graph.rs
Normal file
|
@ -0,0 +1,57 @@
|
|||
use std::io::Write;
|
||||
|
||||
use anyhow::Result;
|
||||
use base_db::{graph, Document, Workspace};
|
||||
use itertools::Itertools;
|
||||
use rustc_hash::FxHashMap;
|
||||
|
||||
pub fn show_dependency_graph(workspace: &Workspace) -> Result<String> {
|
||||
let documents = workspace
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(i, doc)| (doc, format!("v{i:0>5}")))
|
||||
.collect::<FxHashMap<&Document, String>>();
|
||||
|
||||
let mut writer = Vec::new();
|
||||
writeln!(&mut writer, "digraph G {{")?;
|
||||
writeln!(&mut writer, "rankdir = LR;")?;
|
||||
|
||||
for (document, node) in &documents {
|
||||
let label = document.uri.as_str();
|
||||
let shape = if document
|
||||
.data
|
||||
.as_tex()
|
||||
.map_or(false, |data| data.semantics.can_be_root)
|
||||
{
|
||||
"tripleoctagon"
|
||||
} else if document
|
||||
.data
|
||||
.as_tex()
|
||||
.map_or(false, |data| data.semantics.can_be_compiled)
|
||||
{
|
||||
"doubleoctagon"
|
||||
} else {
|
||||
"octagon"
|
||||
};
|
||||
|
||||
writeln!(&mut writer, "\t{node} [label=\"{label}\", shape={shape}];")?;
|
||||
}
|
||||
|
||||
for edge in workspace
|
||||
.iter()
|
||||
.flat_map(|start| graph::Graph::new(workspace, start).edges)
|
||||
.unique()
|
||||
{
|
||||
let source = &documents[edge.source];
|
||||
let target = &documents[edge.target];
|
||||
let label = edge
|
||||
.weight
|
||||
.as_ref()
|
||||
.map_or("<artifact>", |weight| &weight.link.path.text);
|
||||
|
||||
writeln!(&mut writer, "\t{source} -> {target} [label=\"{label}\"];")?;
|
||||
}
|
||||
|
||||
writeln!(&mut writer, "}}")?;
|
||||
Ok(String::from_utf8(writer)?)
|
||||
}
|
5
crates/commands/src/lib.rs
Normal file
5
crates/commands/src/lib.rs
Normal file
|
@ -0,0 +1,5 @@
|
|||
mod change_env;
|
||||
mod clean;
|
||||
mod dep_graph;
|
||||
|
||||
pub use self::{change_env::*, clean::*, dep_graph::*};
|
Loading…
Add table
Add a link
Reference in a new issue