mirror of
https://github.com/rust-lang/rust.git
synced 2025-06-05 03:38:29 +00:00
Merge #5889
5889: Allow logging to file r=matklad a=matklad
bors r+
🤖
Co-authored-by: Aleksey Kladov <aleksey.kladov@gmail.com>
This commit is contained in:
commit
868aaf2bc6
@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
use std::{env, fmt::Write, path::PathBuf};
|
use std::{env, fmt::Write, path::PathBuf};
|
||||||
|
|
||||||
use anyhow::{bail, Result};
|
use anyhow::{bail, format_err, Result};
|
||||||
use pico_args::Arguments;
|
use pico_args::Arguments;
|
||||||
use rust_analyzer::cli::{AnalysisStatsCmd, BenchCmd, BenchWhat, Position, Verbosity};
|
use rust_analyzer::cli::{AnalysisStatsCmd, BenchCmd, BenchWhat, Position, Verbosity};
|
||||||
use ssr::{SsrPattern, SsrRule};
|
use ssr::{SsrPattern, SsrRule};
|
||||||
@ -13,47 +13,107 @@ use vfs::AbsPathBuf;
|
|||||||
|
|
||||||
pub(crate) struct Args {
|
pub(crate) struct Args {
|
||||||
pub(crate) verbosity: Verbosity,
|
pub(crate) verbosity: Verbosity,
|
||||||
|
pub(crate) log_file: Option<PathBuf>,
|
||||||
pub(crate) command: Command,
|
pub(crate) command: Command,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) enum Command {
|
pub(crate) enum Command {
|
||||||
Parse {
|
Parse { no_dump: bool },
|
||||||
no_dump: bool,
|
|
||||||
},
|
|
||||||
Symbols,
|
Symbols,
|
||||||
Highlight {
|
Highlight { rainbow: bool },
|
||||||
rainbow: bool,
|
|
||||||
},
|
|
||||||
AnalysisStats(AnalysisStatsCmd),
|
AnalysisStats(AnalysisStatsCmd),
|
||||||
Bench(BenchCmd),
|
Bench(BenchCmd),
|
||||||
Diagnostics {
|
Diagnostics { path: PathBuf, load_output_dirs: bool, with_proc_macro: bool },
|
||||||
path: PathBuf,
|
Ssr { rules: Vec<SsrRule> },
|
||||||
load_output_dirs: bool,
|
StructuredSearch { debug_snippet: Option<String>, patterns: Vec<SsrPattern> },
|
||||||
with_proc_macro: bool,
|
|
||||||
/// Include files which are not modules. In rust-analyzer
|
|
||||||
/// this would include the parser test files.
|
|
||||||
all: bool,
|
|
||||||
},
|
|
||||||
Ssr {
|
|
||||||
rules: Vec<SsrRule>,
|
|
||||||
},
|
|
||||||
StructuredSearch {
|
|
||||||
debug_snippet: Option<String>,
|
|
||||||
patterns: Vec<SsrPattern>,
|
|
||||||
},
|
|
||||||
ProcMacro,
|
ProcMacro,
|
||||||
RunServer,
|
RunServer,
|
||||||
Version,
|
Version,
|
||||||
Help,
|
Help,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const HELP: &str = "\
|
||||||
|
rust-analyzer
|
||||||
|
|
||||||
|
USAGE:
|
||||||
|
rust-analyzer [FLAGS] [COMMAND] [COMMAND_OPTIONS]
|
||||||
|
|
||||||
|
FLAGS:
|
||||||
|
--version Print version
|
||||||
|
-h, --help Print this help
|
||||||
|
|
||||||
|
-v, --verbose
|
||||||
|
-vv, --spammy
|
||||||
|
-q, --quiet Set verbosity
|
||||||
|
|
||||||
|
--log-file <PATH> Log to the specified filed instead of stderr
|
||||||
|
|
||||||
|
ENVIRONMENTAL VARIABLES:
|
||||||
|
RA_LOG Set log filter in env_logger format
|
||||||
|
RA_PROFILE Enable hierarchical profiler
|
||||||
|
|
||||||
|
COMMANDS:
|
||||||
|
|
||||||
|
not specified Launch LSP server
|
||||||
|
|
||||||
|
parse < main.rs Parse tree
|
||||||
|
--no-dump Suppress printing
|
||||||
|
|
||||||
|
symbols < main.rs Parse input an print the list of symbols
|
||||||
|
|
||||||
|
highlight < main.rs Highlight input as html
|
||||||
|
--rainbow Enable rainbow highlighting of identifiers
|
||||||
|
|
||||||
|
analysis-stats <PATH> Batch typecheck project and print summary statistics
|
||||||
|
<PATH> Directory with Cargo.toml
|
||||||
|
--randomize Randomize order in which crates, modules, and items are processed
|
||||||
|
--parallel Run type inference in parallel
|
||||||
|
--memory-usage Collect memory usage statistics
|
||||||
|
-o, --only <PATH> Only analyze items matching this path
|
||||||
|
--with-deps Also analyze all dependencies
|
||||||
|
--load-output-dirs
|
||||||
|
Load OUT_DIR values by running `cargo check` before analysis
|
||||||
|
--with-proc-macro Use proc-macro-srv for proc-macro expanding
|
||||||
|
|
||||||
|
analysis-bench <PATH> Benchmark specific analysis operation
|
||||||
|
<PATH> Directory with Cargo.toml
|
||||||
|
--highlight <PATH>
|
||||||
|
Compute syntax highlighting for this file
|
||||||
|
--complete <PATH:LINE:COLUMN>
|
||||||
|
Compute completions at this location
|
||||||
|
--goto-def <PATH:LINE:COLUMN>
|
||||||
|
Compute goto definition at this location
|
||||||
|
--memory-usage Collect memory usage statistics
|
||||||
|
--load-output-dirs
|
||||||
|
Load OUT_DIR values by running `cargo check` before analysis
|
||||||
|
--with-proc-macro Use proc-macro-srv for proc-macro expanding
|
||||||
|
|
||||||
|
diagnostics <PATH>
|
||||||
|
<PATH> Directory with Cargo.toml
|
||||||
|
--load-output-dirs
|
||||||
|
Load OUT_DIR values by running `cargo check` before analysis
|
||||||
|
--with-proc-macro Use proc-macro-srv for proc-macro expanding
|
||||||
|
|
||||||
|
ssr [RULE...]
|
||||||
|
<RULE> A structured search replace rule (`$a.foo($b) ==> bar($a, $b)`)
|
||||||
|
|
||||||
|
search [PATTERN..]
|
||||||
|
<PATTERN> A structured search replace pattern (`$a.foo($b)`)
|
||||||
|
--debug <snippet> Prints debug information for any nodes with source exactly
|
||||||
|
equal to <snippet>
|
||||||
|
";
|
||||||
|
|
||||||
impl Args {
|
impl Args {
|
||||||
pub(crate) fn parse() -> Result<Args> {
|
pub(crate) fn parse() -> Result<Args> {
|
||||||
let mut matches = Arguments::from_env();
|
let mut matches = Arguments::from_env();
|
||||||
|
|
||||||
if matches.contains("--version") {
|
if matches.contains("--version") {
|
||||||
matches.finish().or_else(handle_extra_flags)?;
|
matches.finish().or_else(handle_extra_flags)?;
|
||||||
return Ok(Args { verbosity: Verbosity::Normal, command: Command::Version });
|
return Ok(Args {
|
||||||
|
verbosity: Verbosity::Normal,
|
||||||
|
log_file: None,
|
||||||
|
command: Command::Version,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
let verbosity = match (
|
let verbosity = match (
|
||||||
@ -68,168 +128,45 @@ impl Args {
|
|||||||
(false, true, false) => Verbosity::Verbose,
|
(false, true, false) => Verbosity::Verbose,
|
||||||
(false, true, true) => bail!("Invalid flags: -q conflicts with -v"),
|
(false, true, true) => bail!("Invalid flags: -q conflicts with -v"),
|
||||||
};
|
};
|
||||||
|
let log_file = matches.opt_value_from_str("--log-file")?;
|
||||||
|
|
||||||
|
if matches.contains(["-h", "--help"]) {
|
||||||
|
eprintln!("{}", HELP);
|
||||||
|
return Ok(Args { verbosity, log_file: None, command: Command::Help });
|
||||||
|
}
|
||||||
|
|
||||||
let help = Ok(Args { verbosity, command: Command::Help });
|
|
||||||
let subcommand = match matches.subcommand()? {
|
let subcommand = match matches.subcommand()? {
|
||||||
Some(it) => it,
|
Some(it) => it,
|
||||||
None => {
|
None => {
|
||||||
if matches.contains(["-h", "--help"]) {
|
|
||||||
print_subcommands();
|
|
||||||
return help;
|
|
||||||
}
|
|
||||||
matches.finish().or_else(handle_extra_flags)?;
|
matches.finish().or_else(handle_extra_flags)?;
|
||||||
return Ok(Args { verbosity, command: Command::RunServer });
|
return Ok(Args { verbosity, log_file, command: Command::RunServer });
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let command = match subcommand.as_str() {
|
let command = match subcommand.as_str() {
|
||||||
"parse" => {
|
"parse" => Command::Parse { no_dump: matches.contains("--no-dump") },
|
||||||
if matches.contains(["-h", "--help"]) {
|
"symbols" => Command::Symbols,
|
||||||
eprintln!(
|
"highlight" => Command::Highlight { rainbow: matches.contains("--rainbow") },
|
||||||
"\
|
"analysis-stats" => Command::AnalysisStats(AnalysisStatsCmd {
|
||||||
rust-analyzer parse
|
randomize: matches.contains("--randomize"),
|
||||||
|
parallel: matches.contains("--parallel"),
|
||||||
USAGE:
|
memory_usage: matches.contains("--memory-usage"),
|
||||||
rust-analyzer parse [FLAGS]
|
only: matches.opt_value_from_str(["-o", "--only"])?,
|
||||||
|
with_deps: matches.contains("--with-deps"),
|
||||||
FLAGS:
|
load_output_dirs: matches.contains("--load-output-dirs"),
|
||||||
-h, --help Prints help information
|
with_proc_macro: matches.contains("--with-proc-macro"),
|
||||||
--no-dump"
|
path: matches
|
||||||
);
|
.free_from_str()?
|
||||||
return help;
|
.ok_or_else(|| format_err!("expected positional argument"))?,
|
||||||
}
|
}),
|
||||||
|
"analysis-bench" => Command::Bench(BenchCmd {
|
||||||
let no_dump = matches.contains("--no-dump");
|
what: {
|
||||||
matches.finish().or_else(handle_extra_flags)?;
|
let highlight_path: Option<String> =
|
||||||
Command::Parse { no_dump }
|
matches.opt_value_from_str("--highlight")?;
|
||||||
}
|
let complete_path: Option<Position> =
|
||||||
"symbols" => {
|
matches.opt_value_from_str("--complete")?;
|
||||||
if matches.contains(["-h", "--help"]) {
|
let goto_def_path: Option<Position> =
|
||||||
eprintln!(
|
matches.opt_value_from_str("--goto-def")?;
|
||||||
"\
|
match (highlight_path, complete_path, goto_def_path) {
|
||||||
rust-analyzer symbols
|
|
||||||
|
|
||||||
USAGE:
|
|
||||||
rust-analyzer highlight [FLAGS]
|
|
||||||
|
|
||||||
FLAGS:
|
|
||||||
-h, --help Prints help inforamtion"
|
|
||||||
);
|
|
||||||
return help;
|
|
||||||
}
|
|
||||||
|
|
||||||
matches.finish().or_else(handle_extra_flags)?;
|
|
||||||
|
|
||||||
Command::Symbols
|
|
||||||
}
|
|
||||||
"highlight" => {
|
|
||||||
if matches.contains(["-h", "--help"]) {
|
|
||||||
eprintln!(
|
|
||||||
"\
|
|
||||||
rust-analyzer highlight
|
|
||||||
|
|
||||||
USAGE:
|
|
||||||
rust-analyzer highlight [FLAGS]
|
|
||||||
|
|
||||||
FLAGS:
|
|
||||||
-h, --help Prints help information
|
|
||||||
-r, --rainbow"
|
|
||||||
);
|
|
||||||
return help;
|
|
||||||
}
|
|
||||||
|
|
||||||
let rainbow = matches.contains(["-r", "--rainbow"]);
|
|
||||||
matches.finish().or_else(handle_extra_flags)?;
|
|
||||||
Command::Highlight { rainbow }
|
|
||||||
}
|
|
||||||
"analysis-stats" => {
|
|
||||||
if matches.contains(["-h", "--help"]) {
|
|
||||||
eprintln!(
|
|
||||||
"\
|
|
||||||
rust-analyzer analysis-stats
|
|
||||||
|
|
||||||
USAGE:
|
|
||||||
rust-analyzer analysis-stats [FLAGS] [OPTIONS] [PATH]
|
|
||||||
|
|
||||||
FLAGS:
|
|
||||||
-o, --only Only analyze items matching this path
|
|
||||||
-h, --help Prints help information
|
|
||||||
--memory-usage Collect memory usage statistics
|
|
||||||
--randomize Randomize order in which crates, modules, and items are processed
|
|
||||||
--parallel Run type inference in parallel
|
|
||||||
--load-output-dirs Load OUT_DIR values by running `cargo check` before analysis
|
|
||||||
--with-proc-macro Use ra-proc-macro-srv for proc-macro expanding
|
|
||||||
--with-deps Also analyze all dependencies
|
|
||||||
-v, --verbose
|
|
||||||
-q, --quiet
|
|
||||||
|
|
||||||
OPTIONS:
|
|
||||||
-o <ONLY>
|
|
||||||
|
|
||||||
ARGS:
|
|
||||||
<PATH>"
|
|
||||||
);
|
|
||||||
return help;
|
|
||||||
}
|
|
||||||
|
|
||||||
let randomize = matches.contains("--randomize");
|
|
||||||
let parallel = matches.contains("--parallel");
|
|
||||||
let memory_usage = matches.contains("--memory-usage");
|
|
||||||
let only: Option<String> = matches.opt_value_from_str(["-o", "--only"])?;
|
|
||||||
let with_deps: bool = matches.contains("--with-deps");
|
|
||||||
let load_output_dirs = matches.contains("--load-output-dirs");
|
|
||||||
let with_proc_macro = matches.contains("--with-proc-macro");
|
|
||||||
let path = {
|
|
||||||
let mut trailing = matches.free()?;
|
|
||||||
if trailing.len() != 1 {
|
|
||||||
bail!("Invalid flags");
|
|
||||||
}
|
|
||||||
trailing.pop().unwrap().into()
|
|
||||||
};
|
|
||||||
|
|
||||||
Command::AnalysisStats(AnalysisStatsCmd {
|
|
||||||
randomize,
|
|
||||||
parallel,
|
|
||||||
memory_usage,
|
|
||||||
only,
|
|
||||||
with_deps,
|
|
||||||
path,
|
|
||||||
load_output_dirs,
|
|
||||||
with_proc_macro,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
"analysis-bench" => {
|
|
||||||
if matches.contains(["-h", "--help"]) {
|
|
||||||
eprintln!(
|
|
||||||
"\
|
|
||||||
rust-analyzer analysis-bench
|
|
||||||
|
|
||||||
USAGE:
|
|
||||||
rust-analyzer analysis-bench [FLAGS] [OPTIONS]
|
|
||||||
|
|
||||||
FLAGS:
|
|
||||||
-h, --help Prints help information
|
|
||||||
--memory-usage Collect memory usage statistics
|
|
||||||
--load-output-dirs Load OUT_DIR values by running `cargo check` before analysis
|
|
||||||
--with-proc-macro Use ra-proc-macro-srv for proc-macro expanding
|
|
||||||
-v, --verbose
|
|
||||||
|
|
||||||
OPTIONS:
|
|
||||||
--project <PATH> Path to directory with Cargo.toml
|
|
||||||
--complete <PATH:LINE:COLUMN> Compute completions at this location
|
|
||||||
--goto-def <PATH:LINE:COLUMN> Compute goto definition at this location
|
|
||||||
--highlight <PATH> Hightlight this file
|
|
||||||
|
|
||||||
ARGS:
|
|
||||||
<PATH> Project to analyse"
|
|
||||||
);
|
|
||||||
return help;
|
|
||||||
}
|
|
||||||
|
|
||||||
let path: PathBuf = matches.opt_value_from_str("--project")?.unwrap_or_default();
|
|
||||||
let highlight_path: Option<String> = matches.opt_value_from_str("--highlight")?;
|
|
||||||
let complete_path: Option<Position> = matches.opt_value_from_str("--complete")?;
|
|
||||||
let goto_def_path: Option<Position> = matches.opt_value_from_str("--goto-def")?;
|
|
||||||
let what = match (highlight_path, complete_path, goto_def_path) {
|
|
||||||
(Some(path), None, None) => {
|
(Some(path), None, None) => {
|
||||||
let path = env::current_dir().unwrap().join(path);
|
let path = env::current_dir().unwrap().join(path);
|
||||||
BenchWhat::Highlight { path: AbsPathBuf::assert(path) }
|
BenchWhat::Highlight { path: AbsPathBuf::assert(path) }
|
||||||
@ -239,140 +176,52 @@ ARGS:
|
|||||||
_ => panic!(
|
_ => panic!(
|
||||||
"exactly one of `--highlight`, `--complete` or `--goto-def` must be set"
|
"exactly one of `--highlight`, `--complete` or `--goto-def` must be set"
|
||||||
),
|
),
|
||||||
};
|
|
||||||
let memory_usage = matches.contains("--memory-usage");
|
|
||||||
let load_output_dirs = matches.contains("--load-output-dirs");
|
|
||||||
let with_proc_macro = matches.contains("--with-proc-macro");
|
|
||||||
Command::Bench(BenchCmd {
|
|
||||||
memory_usage,
|
|
||||||
path,
|
|
||||||
what,
|
|
||||||
load_output_dirs,
|
|
||||||
with_proc_macro,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
"diagnostics" => {
|
|
||||||
if matches.contains(["-h", "--help"]) {
|
|
||||||
eprintln!(
|
|
||||||
"\
|
|
||||||
rust-analyzer diagnostics
|
|
||||||
|
|
||||||
USAGE:
|
|
||||||
rust-analyzer diagnostics [FLAGS] [PATH]
|
|
||||||
|
|
||||||
FLAGS:
|
|
||||||
-h, --help Prints help information
|
|
||||||
--load-output-dirs Load OUT_DIR values by running `cargo check` before analysis
|
|
||||||
--all Include all files rather than only modules
|
|
||||||
|
|
||||||
ARGS:
|
|
||||||
<PATH>"
|
|
||||||
);
|
|
||||||
return help;
|
|
||||||
}
|
|
||||||
|
|
||||||
let load_output_dirs = matches.contains("--load-output-dirs");
|
|
||||||
let with_proc_macro = matches.contains("--with-proc-macro");
|
|
||||||
let all = matches.contains("--all");
|
|
||||||
let path = {
|
|
||||||
let mut trailing = matches.free()?;
|
|
||||||
if trailing.len() != 1 {
|
|
||||||
bail!("Invalid flags");
|
|
||||||
}
|
|
||||||
trailing.pop().unwrap().into()
|
|
||||||
};
|
|
||||||
|
|
||||||
Command::Diagnostics { path, load_output_dirs, with_proc_macro, all }
|
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
memory_usage: matches.contains("--memory-usage"),
|
||||||
|
load_output_dirs: matches.contains("--load-output-dirs"),
|
||||||
|
with_proc_macro: matches.contains("--with-proc-macro"),
|
||||||
|
path: matches
|
||||||
|
.free_from_str()?
|
||||||
|
.ok_or_else(|| format_err!("expected positional argument"))?,
|
||||||
|
}),
|
||||||
|
"diagnostics" => Command::Diagnostics {
|
||||||
|
load_output_dirs: matches.contains("--load-output-dirs"),
|
||||||
|
with_proc_macro: matches.contains("--with-proc-macro"),
|
||||||
|
path: matches
|
||||||
|
.free_from_str()?
|
||||||
|
.ok_or_else(|| format_err!("expected positional argument"))?,
|
||||||
|
},
|
||||||
"proc-macro" => Command::ProcMacro,
|
"proc-macro" => Command::ProcMacro,
|
||||||
"ssr" => {
|
"ssr" => Command::Ssr {
|
||||||
if matches.contains(["-h", "--help"]) {
|
rules: {
|
||||||
eprintln!(
|
let mut acc = Vec::new();
|
||||||
"\
|
|
||||||
rust-analyzer ssr
|
|
||||||
|
|
||||||
USAGE:
|
|
||||||
rust-analyzer ssr [FLAGS] [RULE...]
|
|
||||||
|
|
||||||
EXAMPLE:
|
|
||||||
rust-analyzer ssr '$a.foo($b) ==> bar($a, $b)'
|
|
||||||
|
|
||||||
FLAGS:
|
|
||||||
--debug <snippet> Prints debug information for any nodes with source exactly equal to <snippet>
|
|
||||||
-h, --help Prints help information
|
|
||||||
|
|
||||||
ARGS:
|
|
||||||
<RULE> A structured search replace rule"
|
|
||||||
);
|
|
||||||
return help;
|
|
||||||
}
|
|
||||||
let mut rules = Vec::new();
|
|
||||||
while let Some(rule) = matches.free_from_str()? {
|
while let Some(rule) = matches.free_from_str()? {
|
||||||
rules.push(rule);
|
acc.push(rule);
|
||||||
}
|
}
|
||||||
Command::Ssr { rules }
|
acc
|
||||||
}
|
},
|
||||||
"search" => {
|
},
|
||||||
if matches.contains(["-h", "--help"]) {
|
"search" => Command::StructuredSearch {
|
||||||
eprintln!(
|
debug_snippet: matches.opt_value_from_str("--debug")?,
|
||||||
"\
|
patterns: {
|
||||||
rust-analyzer search
|
let mut acc = Vec::new();
|
||||||
|
|
||||||
USAGE:
|
|
||||||
rust-analyzer search [FLAGS] [PATTERN...]
|
|
||||||
|
|
||||||
EXAMPLE:
|
|
||||||
rust-analyzer search '$a.foo($b)'
|
|
||||||
|
|
||||||
FLAGS:
|
|
||||||
--debug <snippet> Prints debug information for any nodes with source exactly equal to <snippet>
|
|
||||||
-h, --help Prints help information
|
|
||||||
|
|
||||||
ARGS:
|
|
||||||
<PATTERN> A structured search pattern"
|
|
||||||
);
|
|
||||||
return help;
|
|
||||||
}
|
|
||||||
let debug_snippet = matches.opt_value_from_str("--debug")?;
|
|
||||||
let mut patterns = Vec::new();
|
|
||||||
while let Some(rule) = matches.free_from_str()? {
|
while let Some(rule) = matches.free_from_str()? {
|
||||||
patterns.push(rule);
|
acc.push(rule);
|
||||||
}
|
|
||||||
Command::StructuredSearch { patterns, debug_snippet }
|
|
||||||
}
|
}
|
||||||
|
acc
|
||||||
|
},
|
||||||
|
},
|
||||||
_ => {
|
_ => {
|
||||||
print_subcommands();
|
eprintln!("{}", HELP);
|
||||||
return help;
|
return Ok(Args { verbosity, log_file: None, command: Command::Help });
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
Ok(Args { verbosity, command })
|
matches.finish().or_else(handle_extra_flags)?;
|
||||||
|
Ok(Args { verbosity, log_file, command })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn print_subcommands() {
|
|
||||||
eprintln!(
|
|
||||||
"\
|
|
||||||
rust-analyzer
|
|
||||||
|
|
||||||
USAGE:
|
|
||||||
rust-analyzer <SUBCOMMAND>
|
|
||||||
|
|
||||||
FLAGS:
|
|
||||||
-h, --help Prints help information
|
|
||||||
|
|
||||||
SUBCOMMANDS:
|
|
||||||
analysis-bench
|
|
||||||
analysis-stats
|
|
||||||
highlight
|
|
||||||
diagnostics
|
|
||||||
proc-macro
|
|
||||||
parse
|
|
||||||
search
|
|
||||||
ssr
|
|
||||||
symbols"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn handle_extra_flags(e: pico_args::Error) -> Result<()> {
|
fn handle_extra_flags(e: pico_args::Error) -> Result<()> {
|
||||||
if let pico_args::Error::UnusedArgsLeft(flags) = e {
|
if let pico_args::Error::UnusedArgsLeft(flags) = e {
|
||||||
let mut invalid_flags = String::new();
|
let mut invalid_flags = String::new();
|
||||||
|
73
crates/rust-analyzer/src/bin/logger.rs
Normal file
73
crates/rust-analyzer/src/bin/logger.rs
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
//! Simple logger that logs either to stderr or to a file, using `env_logger`
|
||||||
|
//! filter syntax. Amusingly, there's no crates.io crate that can do this and
|
||||||
|
//! only this.
|
||||||
|
|
||||||
|
use std::{
|
||||||
|
fs::File,
|
||||||
|
io::{BufWriter, Write},
|
||||||
|
};
|
||||||
|
|
||||||
|
use env_logger::filter::{Builder, Filter};
|
||||||
|
use log::{Log, Metadata, Record};
|
||||||
|
use parking_lot::Mutex;
|
||||||
|
|
||||||
|
pub(crate) struct Logger {
|
||||||
|
filter: Filter,
|
||||||
|
file: Option<Mutex<BufWriter<File>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Logger {
|
||||||
|
pub(crate) fn new(log_file: Option<File>, filter: Option<&str>) -> Logger {
|
||||||
|
let filter = {
|
||||||
|
let mut builder = Builder::new();
|
||||||
|
if let Some(filter) = filter {
|
||||||
|
builder.parse(filter);
|
||||||
|
}
|
||||||
|
builder.build()
|
||||||
|
};
|
||||||
|
|
||||||
|
let file = log_file.map(|it| Mutex::new(BufWriter::new(it)));
|
||||||
|
|
||||||
|
Logger { filter, file }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn install(self) {
|
||||||
|
let max_level = self.filter.filter();
|
||||||
|
let _ = log::set_boxed_logger(Box::new(self)).map(|()| log::set_max_level(max_level));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Log for Logger {
|
||||||
|
fn enabled(&self, metadata: &Metadata) -> bool {
|
||||||
|
self.filter.enabled(metadata)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn log(&self, record: &Record) {
|
||||||
|
if !self.filter.matches(record) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
match &self.file {
|
||||||
|
Some(w) => {
|
||||||
|
let _ = writeln!(
|
||||||
|
w.lock(),
|
||||||
|
"[{} {}] {}",
|
||||||
|
record.level(),
|
||||||
|
record.module_path().unwrap_or_default(),
|
||||||
|
record.args(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
None => eprintln!(
|
||||||
|
"[{} {}] {}",
|
||||||
|
record.level(),
|
||||||
|
record.module_path().unwrap_or_default(),
|
||||||
|
record.args(),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn flush(&self) {
|
||||||
|
if let Some(w) = &self.file {
|
||||||
|
let _ = w.lock().flush();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -2,8 +2,9 @@
|
|||||||
//!
|
//!
|
||||||
//! Based on cli flags, either spawns an LSP server, or runs a batch analysis
|
//! Based on cli flags, either spawns an LSP server, or runs a batch analysis
|
||||||
mod args;
|
mod args;
|
||||||
|
mod logger;
|
||||||
|
|
||||||
use std::{convert::TryFrom, process};
|
use std::{convert::TryFrom, env, fs, path::PathBuf, process};
|
||||||
|
|
||||||
use lsp_server::Connection;
|
use lsp_server::Connection;
|
||||||
use project_model::ProjectManifest;
|
use project_model::ProjectManifest;
|
||||||
@ -26,8 +27,8 @@ fn main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn try_main() -> Result<()> {
|
fn try_main() -> Result<()> {
|
||||||
setup_logging()?;
|
|
||||||
let args = args::Args::parse()?;
|
let args = args::Args::parse()?;
|
||||||
|
setup_logging(args.log_file)?;
|
||||||
match args.command {
|
match args.command {
|
||||||
args::Command::RunServer => run_server()?,
|
args::Command::RunServer => run_server()?,
|
||||||
args::Command::ProcMacro => proc_macro_srv::cli::run()?,
|
args::Command::ProcMacro => proc_macro_srv::cli::run()?,
|
||||||
@ -37,8 +38,8 @@ fn try_main() -> Result<()> {
|
|||||||
args::Command::Highlight { rainbow } => cli::highlight(rainbow)?,
|
args::Command::Highlight { rainbow } => cli::highlight(rainbow)?,
|
||||||
args::Command::AnalysisStats(cmd) => cmd.run(args.verbosity)?,
|
args::Command::AnalysisStats(cmd) => cmd.run(args.verbosity)?,
|
||||||
args::Command::Bench(cmd) => cmd.run(args.verbosity)?,
|
args::Command::Bench(cmd) => cmd.run(args.verbosity)?,
|
||||||
args::Command::Diagnostics { path, load_output_dirs, with_proc_macro, all } => {
|
args::Command::Diagnostics { path, load_output_dirs, with_proc_macro } => {
|
||||||
cli::diagnostics(path.as_ref(), load_output_dirs, with_proc_macro, all)?
|
cli::diagnostics(path.as_ref(), load_output_dirs, with_proc_macro)?
|
||||||
}
|
}
|
||||||
args::Command::Ssr { rules } => {
|
args::Command::Ssr { rules } => {
|
||||||
cli::apply_ssr_rules(rules)?;
|
cli::apply_ssr_rules(rules)?;
|
||||||
@ -52,9 +53,21 @@ fn try_main() -> Result<()> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn setup_logging() -> Result<()> {
|
fn setup_logging(log_file: Option<PathBuf>) -> Result<()> {
|
||||||
std::env::set_var("RUST_BACKTRACE", "short");
|
env::set_var("RUST_BACKTRACE", "short");
|
||||||
env_logger::try_init_from_env("RA_LOG")?;
|
|
||||||
|
let log_file = match log_file {
|
||||||
|
Some(path) => {
|
||||||
|
if let Some(parent) = path.parent() {
|
||||||
|
let _ = fs::create_dir_all(parent);
|
||||||
|
}
|
||||||
|
Some(fs::File::create(path)?)
|
||||||
|
}
|
||||||
|
None => None,
|
||||||
|
};
|
||||||
|
let filter = env::var("RA_LOG").ok();
|
||||||
|
logger::Logger::new(log_file, filter.as_deref()).install();
|
||||||
|
|
||||||
profile::init();
|
profile::init();
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -95,7 +108,7 @@ fn run_server() -> Result<()> {
|
|||||||
{
|
{
|
||||||
Some(it) => it,
|
Some(it) => it,
|
||||||
None => {
|
None => {
|
||||||
let cwd = std::env::current_dir()?;
|
let cwd = env::current_dir()?;
|
||||||
AbsPathBuf::assert(cwd)
|
AbsPathBuf::assert(cwd)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -12,12 +12,7 @@ use ide::{DiagnosticsConfig, Severity};
|
|||||||
|
|
||||||
use crate::cli::{load_cargo::load_cargo, Result};
|
use crate::cli::{load_cargo::load_cargo, Result};
|
||||||
|
|
||||||
pub fn diagnostics(
|
pub fn diagnostics(path: &Path, load_output_dirs: bool, with_proc_macro: bool) -> Result<()> {
|
||||||
path: &Path,
|
|
||||||
load_output_dirs: bool,
|
|
||||||
with_proc_macro: bool,
|
|
||||||
_all: bool,
|
|
||||||
) -> Result<()> {
|
|
||||||
let (host, _vfs) = load_cargo(path, load_output_dirs, with_proc_macro)?;
|
let (host, _vfs) = load_cargo(path, load_output_dirs, with_proc_macro)?;
|
||||||
let db = host.raw_database();
|
let db = host.raw_database();
|
||||||
let analysis = host.analysis();
|
let analysis = host.analysis();
|
||||||
|
@ -351,7 +351,7 @@ Relative paths are interpreted relative to `rust-project.json` file location or
|
|||||||
|
|
||||||
See https://github.com/rust-analyzer/rust-project.json-example for a small example.
|
See https://github.com/rust-analyzer/rust-project.json-example for a small example.
|
||||||
|
|
||||||
You can set `RA_LOG` environmental variable to `"'rust_analyzer=info"` to inspect how rust-analyzer handles config and project loading.
|
You can set `RA_LOG` environmental variable to `rust_analyzer=info` to inspect how rust-analyzer handles config and project loading.
|
||||||
|
|
||||||
== Features
|
== Features
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user