1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
|
use std::process::Stdio;
use anyhow::{bail, Result};
use lsp_types::{TextDocumentIdentifier, Url};
use thiserror::Error;
use crate::{db::Workspace, normalize_uri, Db};
pub fn select(db: &dyn Db, name: &str, args: Vec<serde_json::Value>) -> Result<CleanCommand> {
Ok(match name {
"texlab.cleanAuxiliary" => CleanCommand::new(db, CleanOptions::Auxiliary, args)?,
"texlab.cleanArtifacts" => CleanCommand::new(db, CleanOptions::Artifacts, args)?,
_ => bail!("Unknown command: {}", name),
})
}
#[derive(Debug, Error)]
pub enum CleanError {
#[error("document '{0}' not found")]
DocumentNotFound(Url),
#[error("document '{0}' is not a local file")]
NoLocalFile(Url),
#[error("document was not provided as an argument")]
MissingArg,
#[error("invalid argument: {0}")]
InvalidArg(serde_json::Error),
#[error("failed to spawn process: {0}")]
Spawn(std::io::Error),
}
#[derive(Debug)]
pub struct CleanCommand {
executable: String,
args: Vec<String>,
}
impl CleanCommand {
fn new(db: &dyn Db, options: CleanOptions, args: Vec<serde_json::Value>) -> Result<Self> {
let params: TextDocumentIdentifier =
serde_json::from_value(args.into_iter().next().ok_or(CleanError::MissingArg)?)
.map_err(CleanError::InvalidArg)?;
let mut uri = params.uri;
normalize_uri(&mut uri);
let workspace = Workspace::get(db);
let document = workspace
.lookup_uri(db, &uri)
.ok_or_else(|| CleanError::DocumentNotFound(uri.clone()))?;
let working_dir = workspace.working_dir(db, document.directory(db));
let output_dir = workspace
.output_dir(db, working_dir)
.path(db)
.as_deref()
.ok_or_else(|| CleanError::NoLocalFile(uri.clone()))?;
let path = document
.location(db)
.path(db)
.as_deref()
.ok_or_else(|| CleanError::NoLocalFile(uri.clone()))?;
let flag = match options {
CleanOptions::Auxiliary => "-c",
CleanOptions::Artifacts => "-C",
};
let executable = "latexmk".to_string();
let args = vec![
format!("-outdir={}", output_dir.display()),
flag.to_string(),
path.display().to_string(),
];
Ok(Self { executable, args })
}
pub fn run(self) -> Result<(), CleanError> {
log::debug!("Cleaning output files: {} {:?}", self.executable, self.args);
std::process::Command::new(self.executable)
.args(self.args)
.stdin(Stdio::null())
.stdout(Stdio::null())
.stderr(Stdio::null())
.status()
.map_err(CleanError::Spawn)?;
Ok(())
}
}
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash)]
enum CleanOptions {
Auxiliary,
Artifacts,
}
|