diff options
-rw-r--r-- | .vscode/launch.json | 6 | ||||
-rw-r--r-- | crates/rust-analyzer/src/bin/args.rs | 48 | ||||
-rw-r--r-- | crates/rust-analyzer/src/bin/logger.rs | 39 | ||||
-rw-r--r-- | crates/rust-analyzer/src/bin/main.rs | 17 | ||||
-rw-r--r-- | docs/dev/debugging.md | 8 |
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; | |||
14 | pub(crate) struct Args { | 14 | pub(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 | ||
20 | pub(crate) enum Command { | 22 | pub(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 | ||
52 | ENVIRONMENTAL VARIABLES: | 59 | ENVIRONMENTAL 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 | ||
56 | COMMANDS: | 64 | COMMANDS: |
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 | ||
5 | use std::{ | 5 | use std::{ |
6 | fs::File, | 6 | fs::File, |
7 | io::{BufWriter, Write}, | 7 | io::{self, BufWriter, Write}, |
8 | }; | 8 | }; |
9 | 9 | ||
10 | use env_logger::filter::{Builder, Filter}; | 10 | use env_logger::filter::{Builder, Filter}; |
@@ -14,10 +14,11 @@ use parking_lot::Mutex; | |||
14 | pub(crate) struct Logger { | 14 | pub(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 | ||
19 | impl Logger { | 20 | impl 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 | ||
22 | fn main() { | 22 | fn 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 | ||
29 | fn try_main() -> Result<()> { | 30 | fn 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 | ||
59 | fn setup_logging(log_file: Option<PathBuf>) -> Result<()> { | 70 | fn 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 | ||
60 | If 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). |