Configuration plumbing for cargo watcher

This commit is contained in:
Emil Lauridsen
2019-12-25 16:50:38 +01:00
parent 41a1ec723c
commit 6af4bf7a8d
7 changed files with 85 additions and 86 deletions

View File

@@ -1,3 +1,4 @@
use crate::world::Options;
use cargo_metadata::{ use cargo_metadata::{
diagnostic::{ diagnostic::{
Applicability, Diagnostic as RustDiagnostic, DiagnosticLevel, DiagnosticSpan, Applicability, Diagnostic as RustDiagnostic, DiagnosticLevel, DiagnosticSpan,
@@ -30,14 +31,17 @@ pub struct CheckWatcher {
} }
impl CheckWatcher { impl CheckWatcher {
pub fn new(workspace_root: PathBuf) -> CheckWatcher { pub fn new(options: &Options, workspace_root: PathBuf) -> CheckWatcher {
let check_command = options.cargo_check_command.clone();
let check_args = options.cargo_check_args.clone();
let shared = Arc::new(RwLock::new(CheckWatcherSharedState::new())); let shared = Arc::new(RwLock::new(CheckWatcherSharedState::new()));
let (task_send, task_recv) = unbounded::<CheckTask>(); let (task_send, task_recv) = unbounded::<CheckTask>();
let (cmd_send, cmd_recv) = unbounded::<CheckCommand>(); let (cmd_send, cmd_recv) = unbounded::<CheckCommand>();
let shared_ = shared.clone(); let shared_ = shared.clone();
let handle = std::thread::spawn(move || { let handle = std::thread::spawn(move || {
let mut check = CheckWatcherState::new(shared_, workspace_root); let mut check =
CheckWatcherState::new(check_command, check_args, workspace_root, shared_);
check.run(&task_send, &cmd_recv); check.run(&task_send, &cmd_recv);
}); });
@@ -50,6 +54,8 @@ impl CheckWatcher {
} }
pub struct CheckWatcherState { pub struct CheckWatcherState {
check_command: Option<String>,
check_args: Vec<String>,
workspace_root: PathBuf, workspace_root: PathBuf,
running: bool, running: bool,
watcher: WatchThread, watcher: WatchThread,
@@ -134,11 +140,21 @@ pub enum CheckCommand {
impl CheckWatcherState { impl CheckWatcherState {
pub fn new( pub fn new(
shared: Arc<RwLock<CheckWatcherSharedState>>, check_command: Option<String>,
check_args: Vec<String>,
workspace_root: PathBuf, workspace_root: PathBuf,
shared: Arc<RwLock<CheckWatcherSharedState>>,
) -> CheckWatcherState { ) -> CheckWatcherState {
let watcher = WatchThread::new(&workspace_root); let watcher = WatchThread::new(check_command.as_ref(), &check_args, &workspace_root);
CheckWatcherState { workspace_root, running: false, watcher, last_update_req: None, shared } CheckWatcherState {
check_command,
check_args,
workspace_root,
running: false,
watcher,
last_update_req: None,
shared,
}
} }
pub fn run(&mut self, task_send: &Sender<CheckTask>, cmd_recv: &Receiver<CheckCommand>) { pub fn run(&mut self, task_send: &Sender<CheckTask>, cmd_recv: &Receiver<CheckCommand>) {
@@ -163,7 +179,11 @@ impl CheckWatcherState {
self.shared.write().clear(task_send); self.shared.write().clear(task_send);
self.watcher.cancel(); self.watcher.cancel();
self.watcher = WatchThread::new(&self.workspace_root); self.watcher = WatchThread::new(
self.check_command.as_ref(),
&self.check_args,
&self.workspace_root,
);
} }
} }
} }
@@ -229,13 +249,25 @@ struct WatchThread {
} }
impl WatchThread { impl WatchThread {
fn new(workspace_root: &PathBuf) -> WatchThread { fn new(
let manifest_path = format!("{}/Cargo.toml", workspace_root.to_string_lossy()); check_command: Option<&String>,
check_args: &[String],
workspace_root: &PathBuf,
) -> WatchThread {
let check_command = check_command.cloned().unwrap_or("check".to_string());
let mut args: Vec<String> = vec![
check_command,
"--message-format=json".to_string(),
"--manifest-path".to_string(),
format!("{}/Cargo.toml", workspace_root.to_string_lossy()),
];
args.extend(check_args.iter().cloned());
let (message_send, message_recv) = unbounded(); let (message_send, message_recv) = unbounded();
let (cancel_send, cancel_recv) = unbounded(); let (cancel_send, cancel_recv) = unbounded();
std::thread::spawn(move || { std::thread::spawn(move || {
let mut command = Command::new("cargo") let mut command = Command::new("cargo")
.args(&["check", "--message-format=json", "--manifest-path", &manifest_path]) .args(&args)
.stdout(Stdio::piped()) .stdout(Stdio::piped())
.stderr(Stdio::null()) .stderr(Stdio::null())
.spawn() .spawn()

View File

@@ -32,6 +32,10 @@ pub struct ServerConfig {
pub max_inlay_hint_length: Option<usize>, pub max_inlay_hint_length: Option<usize>,
pub cargo_check_enable: bool,
pub cargo_check_command: Option<String>,
pub cargo_check_args: Vec<String>,
/// For internal usage to make integrated tests faster. /// For internal usage to make integrated tests faster.
#[serde(deserialize_with = "nullable_bool_true")] #[serde(deserialize_with = "nullable_bool_true")]
pub with_sysroot: bool, pub with_sysroot: bool,
@@ -51,6 +55,9 @@ impl Default for ServerConfig {
use_client_watching: false, use_client_watching: false,
lru_capacity: None, lru_capacity: None,
max_inlay_hint_length: None, max_inlay_hint_length: None,
cargo_check_enable: true,
cargo_check_command: None,
cargo_check_args: vec![],
with_sysroot: true, with_sysroot: true,
feature_flags: FxHashMap::default(), feature_flags: FxHashMap::default(),
cargo_features: Default::default(), cargo_features: Default::default(),

View File

@@ -127,6 +127,9 @@ pub fn main_loop(
.and_then(|it| it.line_folding_only) .and_then(|it| it.line_folding_only)
.unwrap_or(false), .unwrap_or(false),
max_inlay_hint_length: config.max_inlay_hint_length, max_inlay_hint_length: config.max_inlay_hint_length,
cargo_check_enable: config.cargo_check_enable,
cargo_check_command: config.cargo_check_command,
cargo_check_args: config.cargo_check_args,
} }
}; };

View File

@@ -35,6 +35,9 @@ pub struct Options {
pub supports_location_link: bool, pub supports_location_link: bool,
pub line_folding_only: bool, pub line_folding_only: bool,
pub max_inlay_hint_length: Option<usize>, pub max_inlay_hint_length: Option<usize>,
pub cargo_check_enable: bool,
pub cargo_check_command: Option<String>,
pub cargo_check_args: Vec<String>,
} }
/// `WorldState` is the primary mutable state of the language server /// `WorldState` is the primary mutable state of the language server
@@ -131,7 +134,7 @@ impl WorldState {
change.set_crate_graph(crate_graph); change.set_crate_graph(crate_graph);
// FIXME: Figure out the multi-workspace situation // FIXME: Figure out the multi-workspace situation
let check_watcher = CheckWatcher::new(folder_roots.first().cloned().unwrap()); let check_watcher = CheckWatcher::new(&options, folder_roots.first().cloned().unwrap());
let mut analysis_host = AnalysisHost::new(lru_capacity, feature_flags); let mut analysis_host = AnalysisHost::new(lru_capacity, feature_flags);
analysis_host.apply_change(change); analysis_host.apply_change(change);

View File

@@ -188,20 +188,10 @@
"default": "ra_lsp_server", "default": "ra_lsp_server",
"description": "Path to ra_lsp_server executable" "description": "Path to ra_lsp_server executable"
}, },
"rust-analyzer.enableCargoWatchOnStartup": { "rust-analyzer.enableCargoCheck": {
"type": "string", "type": "boolean",
"default": "ask", "default": true,
"enum": [ "description": "Run `cargo check` for diagnostics on save"
"ask",
"enabled",
"disabled"
],
"enumDescriptions": [
"Asks each time whether to run `cargo watch`",
"`cargo watch` is always started",
"Don't start `cargo watch`"
],
"description": "Whether to run `cargo watch` on startup"
}, },
"rust-analyzer.excludeGlobs": { "rust-analyzer.excludeGlobs": {
"type": "array", "type": "array",
@@ -213,25 +203,15 @@
"default": true, "default": true,
"description": "client provided file watching instead of notify watching." "description": "client provided file watching instead of notify watching."
}, },
"rust-analyzer.cargo-watch.arguments": { "rust-analyzer.cargo-check.arguments": {
"type": "string",
"description": "`cargo-watch` arguments. (e.g: `--features=\"shumway,pdf\"` will run as `cargo watch -x \"check --features=\"shumway,pdf\"\"` )",
"default": ""
},
"rust-analyzer.cargo-watch.command": {
"type": "string",
"description": "`cargo-watch` command. (e.g: `clippy` will run as `cargo watch -x clippy` )",
"default": "check"
},
"rust-analyzer.cargo-watch.ignore": {
"type": "array", "type": "array",
"description": "A list of patterns for cargo-watch to ignore (will be passed as `--ignore`)", "description": "`cargo-check` arguments. (e.g: `--features=\"shumway,pdf\"` will run as `cargo check --features=\"shumway,pdf\"` )",
"default": [] "default": []
}, },
"rust-analyzer.cargo-watch.allTargets": { "rust-analyzer.cargo-check.command": {
"type": "boolean", "type": "string",
"description": "Check all targets and tests (will be passed as `--all-targets`)", "description": "`cargo-check` command. (e.g: `clippy` will run as `cargo clippy` )",
"default": true "default": "check"
}, },
"rust-analyzer.trace.server": { "rust-analyzer.trace.server": {
"type": "string", "type": "string",

View File

@@ -4,16 +4,10 @@ import { Server } from './server';
const RA_LSP_DEBUG = process.env.__RA_LSP_SERVER_DEBUG; const RA_LSP_DEBUG = process.env.__RA_LSP_SERVER_DEBUG;
export type CargoWatchStartupOptions = 'ask' | 'enabled' | 'disabled'; export interface CargoCheckOptions {
export type CargoWatchTraceOptions = 'off' | 'error' | 'verbose'; enabled: boolean;
arguments: string[];
export interface CargoWatchOptions { command: null | string;
enableOnStartup: CargoWatchStartupOptions;
arguments: string;
command: string;
trace: CargoWatchTraceOptions;
ignore: string[];
allTargets: boolean;
} }
export interface CargoFeatures { export interface CargoFeatures {
@@ -35,13 +29,10 @@ export class Config {
public featureFlags = {}; public featureFlags = {};
// for internal use // for internal use
public withSysroot: null | boolean = null; public withSysroot: null | boolean = null;
public cargoWatchOptions: CargoWatchOptions = { public cargoCheckOptions: CargoCheckOptions = {
enableOnStartup: 'ask', enabled: true,
trace: 'off', arguments: [],
arguments: '', command: null,
command: '',
ignore: [],
allTargets: true,
}; };
public cargoFeatures: CargoFeatures = { public cargoFeatures: CargoFeatures = {
noDefaultFeatures: false, noDefaultFeatures: false,
@@ -100,44 +91,24 @@ export class Config {
RA_LSP_DEBUG || (config.get('raLspServerPath') as string); RA_LSP_DEBUG || (config.get('raLspServerPath') as string);
} }
if (config.has('enableCargoWatchOnStartup')) { if (config.has('enableCargoCheck')) {
this.cargoWatchOptions.enableOnStartup = config.get< this.cargoCheckOptions.enabled = config.get<boolean>(
CargoWatchStartupOptions 'enableCargoCheck',
>('enableCargoWatchOnStartup', 'ask'); true,
}
if (config.has('trace.cargo-watch')) {
this.cargoWatchOptions.trace = config.get<CargoWatchTraceOptions>(
'trace.cargo-watch',
'off',
); );
} }
if (config.has('cargo-watch.arguments')) { if (config.has('cargo-watch.arguments')) {
this.cargoWatchOptions.arguments = config.get<string>( this.cargoCheckOptions.arguments = config.get<string[]>(
'cargo-watch.arguments', 'cargo-watch.arguments',
'',
);
}
if (config.has('cargo-watch.command')) {
this.cargoWatchOptions.command = config.get<string>(
'cargo-watch.command',
'',
);
}
if (config.has('cargo-watch.ignore')) {
this.cargoWatchOptions.ignore = config.get<string[]>(
'cargo-watch.ignore',
[], [],
); );
} }
if (config.has('cargo-watch.allTargets')) { if (config.has('cargo-watch.command')) {
this.cargoWatchOptions.allTargets = config.get<boolean>( this.cargoCheckOptions.command = config.get<string>(
'cargo-watch.allTargets', 'cargo-watch.command',
true, '',
); );
} }

View File

@@ -55,6 +55,9 @@ export class Server {
publishDecorations: true, publishDecorations: true,
lruCapacity: Server.config.lruCapacity, lruCapacity: Server.config.lruCapacity,
maxInlayHintLength: Server.config.maxInlayHintLength, maxInlayHintLength: Server.config.maxInlayHintLength,
cargoCheckEnable: Server.config.cargoCheckOptions.enabled,
cargoCheckCommand: Server.config.cargoCheckOptions.command,
cargoCheckArgs: Server.config.cargoCheckOptions.arguments,
excludeGlobs: Server.config.excludeGlobs, excludeGlobs: Server.config.excludeGlobs,
useClientWatching: Server.config.useClientWatching, useClientWatching: Server.config.useClientWatching,
featureFlags: Server.config.featureFlags, featureFlags: Server.config.featureFlags,