aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.vscode/launch.json6
-rw-r--r--crates/rust-analyzer/src/bin/args.rs48
-rw-r--r--crates/rust-analyzer/src/bin/logger.rs39
-rw-r--r--crates/rust-analyzer/src/bin/main.rs17
-rw-r--r--docs/dev/debugging.md8
5 files changed, 97 insertions, 21 deletions
diff --git a/.vscode/launch.json b/.vscode/launch.json
index 8ca27d878..021b8f048 100644
--- a/.vscode/launch.json
+++ b/.vscode/launch.json
@@ -120,6 +120,12 @@
120 "sourceMaps": true, 120 "sourceMaps": true,
121 "outFiles": [ "${workspaceFolder}/editors/code/out/tests/unit/**/*.js" ], 121 "outFiles": [ "${workspaceFolder}/editors/code/out/tests/unit/**/*.js" ],
122 "preLaunchTask": "Pretest" 122 "preLaunchTask": "Pretest"
123 },
124 {
125 "name": "Win Attach to Server",
126 "type": "cppvsdbg",
127 "processId":"${command:pickProcess}",
128 "request": "attach"
123 } 129 }
124 ] 130 ]
125} 131}
diff --git a/crates/rust-analyzer/src/bin/args.rs b/crates/rust-analyzer/src/bin/args.rs
index 7d917946e..37d8414f4 100644
--- a/crates/rust-analyzer/src/bin/args.rs
+++ b/crates/rust-analyzer/src/bin/args.rs
@@ -14,7 +14,9 @@ use vfs::AbsPathBuf;
14pub(crate) struct Args { 14pub(crate) struct Args {
15 pub(crate) verbosity: Verbosity, 15 pub(crate) verbosity: Verbosity,
16 pub(crate) log_file: Option<PathBuf>, 16 pub(crate) log_file: Option<PathBuf>,
17 pub(crate) no_buffering: bool,
17 pub(crate) command: Command, 18 pub(crate) command: Command,
19 pub(crate) wait_dbg: bool,
18} 20}
19 21
20pub(crate) enum Command { 22pub(crate) enum Command {
@@ -47,11 +49,17 @@ FLAGS:
47 -vv, --spammy 49 -vv, --spammy
48 -q, --quiet Set verbosity 50 -q, --quiet Set verbosity
49 51
50 --log-file <PATH> Log to the specified filed instead of stderr 52 --log-file <PATH> Log to the specified file instead of stderr
53 --no-log-buffering
54 Flush log records to the file immediately
55
56 --wait-dbg Wait until a debugger is attached to.
57 The flag is valid for debug builds only
51 58
52ENVIRONMENTAL VARIABLES: 59ENVIRONMENTAL VARIABLES:
53 RA_LOG Set log filter in env_logger format 60 RA_LOG Set log filter in env_logger format
54 RA_PROFILE Enable hierarchical profiler 61 RA_PROFILE Enable hierarchical profiler
62 RA_WAIT_DBG If set acts like a --wait-dbg flag
55 63
56COMMANDS: 64COMMANDS:
57 65
@@ -114,6 +122,8 @@ impl Args {
114 verbosity: Verbosity::Normal, 122 verbosity: Verbosity::Normal,
115 log_file: None, 123 log_file: None,
116 command: Command::Version, 124 command: Command::Version,
125 no_buffering: false,
126 wait_dbg: false,
117 }); 127 });
118 } 128 }
119 129
@@ -130,21 +140,41 @@ impl Args {
130 (false, true, true) => bail!("Invalid flags: -q conflicts with -v"), 140 (false, true, true) => bail!("Invalid flags: -q conflicts with -v"),
131 }; 141 };
132 let log_file = matches.opt_value_from_str("--log-file")?; 142 let log_file = matches.opt_value_from_str("--log-file")?;
143 let no_buffering = matches.contains("--no-log-buffering");
144 let wait_dbg = matches.contains("--wait-dbg");
133 145
134 if matches.contains(["-h", "--help"]) { 146 if matches.contains(["-h", "--help"]) {
135 eprintln!("{}", HELP); 147 eprintln!("{}", HELP);
136 return Ok(Args { verbosity, log_file: None, command: Command::Help }); 148 return Ok(Args {
149 verbosity,
150 log_file: None,
151 command: Command::Help,
152 no_buffering,
153 wait_dbg,
154 });
137 } 155 }
138 156
139 if matches.contains("--print-config-schema") { 157 if matches.contains("--print-config-schema") {
140 return Ok(Args { verbosity, log_file, command: Command::PrintConfigSchema }); 158 return Ok(Args {
159 verbosity,
160 log_file,
161 command: Command::PrintConfigSchema,
162 no_buffering,
163 wait_dbg,
164 });
141 } 165 }
142 166
143 let subcommand = match matches.subcommand()? { 167 let subcommand = match matches.subcommand()? {
144 Some(it) => it, 168 Some(it) => it,
145 None => { 169 None => {
146 finish_args(matches)?; 170 finish_args(matches)?;
147 return Ok(Args { verbosity, log_file, command: Command::RunServer }); 171 return Ok(Args {
172 verbosity,
173 log_file,
174 command: Command::RunServer,
175 no_buffering,
176 wait_dbg,
177 });
148 } 178 }
149 }; 179 };
150 let command = match subcommand.as_str() { 180 let command = match subcommand.as_str() {
@@ -219,11 +249,17 @@ impl Args {
219 }, 249 },
220 _ => { 250 _ => {
221 eprintln!("{}", HELP); 251 eprintln!("{}", HELP);
222 return Ok(Args { verbosity, log_file: None, command: Command::Help }); 252 return Ok(Args {
253 verbosity,
254 log_file: None,
255 command: Command::Help,
256 no_buffering,
257 wait_dbg,
258 });
223 } 259 }
224 }; 260 };
225 finish_args(matches)?; 261 finish_args(matches)?;
226 Ok(Args { verbosity, log_file, command }) 262 Ok(Args { verbosity, log_file, command, no_buffering, wait_dbg })
227 } 263 }
228} 264}
229 265
diff --git a/crates/rust-analyzer/src/bin/logger.rs b/crates/rust-analyzer/src/bin/logger.rs
index 3bcb1ae37..14887c5cc 100644
--- a/crates/rust-analyzer/src/bin/logger.rs
+++ b/crates/rust-analyzer/src/bin/logger.rs
@@ -4,7 +4,7 @@
4 4
5use std::{ 5use std::{
6 fs::File, 6 fs::File,
7 io::{BufWriter, Write}, 7 io::{self, BufWriter, Write},
8}; 8};
9 9
10use env_logger::filter::{Builder, Filter}; 10use env_logger::filter::{Builder, Filter};
@@ -14,10 +14,11 @@ use parking_lot::Mutex;
14pub(crate) struct Logger { 14pub(crate) struct Logger {
15 filter: Filter, 15 filter: Filter,
16 file: Option<Mutex<BufWriter<File>>>, 16 file: Option<Mutex<BufWriter<File>>>,
17 no_buffering: bool,
17} 18}
18 19
19impl Logger { 20impl Logger {
20 pub(crate) fn new(log_file: Option<File>, filter: Option<&str>) -> Logger { 21 pub(crate) fn new(log_file: Option<File>, no_buffering: bool, filter: Option<&str>) -> Logger {
21 let filter = { 22 let filter = {
22 let mut builder = Builder::new(); 23 let mut builder = Builder::new();
23 if let Some(filter) = filter { 24 if let Some(filter) = filter {
@@ -28,7 +29,7 @@ impl Logger {
28 29
29 let file = log_file.map(|it| Mutex::new(BufWriter::new(it))); 30 let file = log_file.map(|it| Mutex::new(BufWriter::new(it)));
30 31
31 Logger { filter, file } 32 Logger { filter, file, no_buffering }
32 } 33 }
33 34
34 pub(crate) fn install(self) { 35 pub(crate) fn install(self) {
@@ -46,7 +47,8 @@ impl Log for Logger {
46 if !self.filter.matches(record) { 47 if !self.filter.matches(record) {
47 return; 48 return;
48 } 49 }
49 match &self.file { 50
51 let should_flush = match &self.file {
50 Some(w) => { 52 Some(w) => {
51 let _ = writeln!( 53 let _ = writeln!(
52 w.lock(), 54 w.lock(),
@@ -55,19 +57,32 @@ impl Log for Logger {
55 record.module_path().unwrap_or_default(), 57 record.module_path().unwrap_or_default(),
56 record.args(), 58 record.args(),
57 ); 59 );
60 self.no_buffering
61 }
62 None => {
63 eprintln!(
64 "[{} {}] {}",
65 record.level(),
66 record.module_path().unwrap_or_default(),
67 record.args(),
68 );
69 true // flush stderr unconditionally
58 } 70 }
59 None => eprintln!( 71 };
60 "[{} {}] {}", 72
61 record.level(), 73 if should_flush {
62 record.module_path().unwrap_or_default(), 74 self.flush();
63 record.args(),
64 ),
65 } 75 }
66 } 76 }
67 77
68 fn flush(&self) { 78 fn flush(&self) {
69 if let Some(w) = &self.file { 79 match &self.file {
70 let _ = w.lock().flush(); 80 Some(w) => {
81 let _ = w.lock().flush();
82 }
83 None => {
84 let _ = io::stderr().flush();
85 }
71 } 86 }
72 } 87 }
73} 88}
diff --git a/crates/rust-analyzer/src/bin/main.rs b/crates/rust-analyzer/src/bin/main.rs
index bee2eedbc..088b17b03 100644
--- a/crates/rust-analyzer/src/bin/main.rs
+++ b/crates/rust-analyzer/src/bin/main.rs
@@ -21,6 +21,7 @@ static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;
21 21
22fn main() { 22fn main() {
23 if let Err(err) = try_main() { 23 if let Err(err) = try_main() {
24 log::error!("Unexpected error: {}", err);
24 eprintln!("{}", err); 25 eprintln!("{}", err);
25 process::exit(101); 26 process::exit(101);
26 } 27 }
@@ -28,7 +29,17 @@ fn main() {
28 29
29fn try_main() -> Result<()> { 30fn try_main() -> Result<()> {
30 let args = args::Args::parse()?; 31 let args = args::Args::parse()?;
31 setup_logging(args.log_file)?; 32
33 #[cfg(debug_assertions)]
34 if args.wait_dbg || env::var("RA_WAIT_DBG").is_ok() {
35 #[allow(unused_mut)]
36 let mut d = 4;
37 while d == 4 {
38 d = 4;
39 }
40 }
41
42 setup_logging(args.log_file, args.no_buffering)?;
32 match args.command { 43 match args.command {
33 args::Command::RunServer => run_server()?, 44 args::Command::RunServer => run_server()?,
34 args::Command::PrintConfigSchema => { 45 args::Command::PrintConfigSchema => {
@@ -56,7 +67,7 @@ fn try_main() -> Result<()> {
56 Ok(()) 67 Ok(())
57} 68}
58 69
59fn setup_logging(log_file: Option<PathBuf>) -> Result<()> { 70fn setup_logging(log_file: Option<PathBuf>, no_buffering: bool) -> Result<()> {
60 env::set_var("RUST_BACKTRACE", "short"); 71 env::set_var("RUST_BACKTRACE", "short");
61 72
62 let log_file = match log_file { 73 let log_file = match log_file {
@@ -69,7 +80,7 @@ fn setup_logging(log_file: Option<PathBuf>) -> Result<()> {
69 None => None, 80 None => None,
70 }; 81 };
71 let filter = env::var("RA_LOG").ok(); 82 let filter = env::var("RA_LOG").ok();
72 logger::Logger::new(log_file, filter.as_deref()).install(); 83 logger::Logger::new(log_file, no_buffering, filter.as_deref()).install();
73 84
74 tracing_setup::setup_tracing()?; 85 tracing_setup::setup_tracing()?;
75 86
diff --git a/docs/dev/debugging.md b/docs/dev/debugging.md
index 8c48fd5a1..cc7a790ff 100644
--- a/docs/dev/debugging.md
+++ b/docs/dev/debugging.md
@@ -57,6 +57,14 @@ To apply changes to an already running debug process, press <kbd>Ctrl+Shift+P</k
57 57
58- Go back to the `[Extension Development Host]` instance and hover over a Rust variable and your breakpoint should hit. 58- Go back to the `[Extension Development Host]` instance and hover over a Rust variable and your breakpoint should hit.
59 59
60If you need to debug the server from the very beginning, including its initialization code, you can use the `--wait-dbg` command line argument or `RA_WAIT_DBG` environment variable. The server will spin at the beginning of the `try_main` function (see `crates\rust-analyzer\src\bin\main.rs`)
61```rust
62 let mut d = 4;
63 while d == 4 { // set a breakpoint here and change the value
64 d = 4;
65 }
66```
67
60## Demo 68## Demo
61 69
62- [Debugging TypeScript VScode extension](https://www.youtube.com/watch?v=T-hvpK6s4wM). 70- [Debugging TypeScript VScode extension](https://www.youtube.com/watch?v=T-hvpK6s4wM).