mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2026-03-12 20:00:31 +00:00
feat: add --json flag to rust-analyzer parse
This commit is contained in:
parent
a1b86d600f
commit
6ff82f9030
@ -40,6 +40,8 @@ xflags::xflags! {
|
||||
cmd parse {
|
||||
/// Suppress printing.
|
||||
optional --no-dump
|
||||
/// Output as JSON.
|
||||
optional --json
|
||||
}
|
||||
|
||||
/// Parse stdin and print the list of symbols.
|
||||
@ -233,6 +235,7 @@ pub struct LspServer {
|
||||
#[derive(Debug)]
|
||||
pub struct Parse {
|
||||
pub no_dump: bool,
|
||||
pub json: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
@ -257,8 +260,8 @@ pub struct AnalysisStats {
|
||||
pub disable_build_scripts: bool,
|
||||
pub disable_proc_macros: bool,
|
||||
pub proc_macro_srv: Option<PathBuf>,
|
||||
pub skip_lowering: bool,
|
||||
pub skip_lang_items: bool,
|
||||
pub skip_lowering: bool,
|
||||
pub skip_inference: bool,
|
||||
pub skip_mir_stats: bool,
|
||||
pub skip_data_layout: bool,
|
||||
|
||||
@ -1,18 +1,101 @@
|
||||
//! Read Rust code on stdin, print syntax tree on stdout.
|
||||
use ide::Edition;
|
||||
use syntax::{AstNode, SourceFile};
|
||||
use ide_db::line_index::LineIndex;
|
||||
use serde::Serialize;
|
||||
use syntax::{AstNode, NodeOrToken, SourceFile, SyntaxNode, SyntaxToken};
|
||||
|
||||
use crate::cli::{flags, read_stdin};
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct JsonNode {
|
||||
kind: String,
|
||||
#[serde(rename = "type")]
|
||||
node_type: &'static str,
|
||||
start: [u32; 3],
|
||||
end: [u32; 3],
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
text: Option<String>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
children: Option<Vec<JsonNode>>,
|
||||
}
|
||||
|
||||
fn pos(line_index: &LineIndex, offset: syntax::TextSize) -> [u32; 3] {
|
||||
let offset_u32 = u32::from(offset);
|
||||
let line_col = line_index.line_col(offset);
|
||||
[offset_u32, line_col.line, line_col.col]
|
||||
}
|
||||
|
||||
impl flags::Parse {
|
||||
pub fn run(self) -> anyhow::Result<()> {
|
||||
let _p = tracing::info_span!("flags::Parse::run").entered();
|
||||
let text = read_stdin()?;
|
||||
let line_index = LineIndex::new(&text);
|
||||
let file = SourceFile::parse(&text, Edition::CURRENT).tree();
|
||||
|
||||
if !self.no_dump {
|
||||
println!("{:#?}", file.syntax());
|
||||
if self.json {
|
||||
let json_tree = node_to_json(NodeOrToken::Node(file.syntax().clone()), &line_index);
|
||||
println!("{}", serde_json::to_string(&json_tree)?);
|
||||
} else {
|
||||
println!("{:#?}", file.syntax());
|
||||
}
|
||||
}
|
||||
|
||||
std::mem::forget(file);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn node_to_json(node: NodeOrToken<SyntaxNode, SyntaxToken>, line_index: &LineIndex) -> JsonNode {
|
||||
let range = node.text_range();
|
||||
let kind = format!("{:?}", node.kind());
|
||||
|
||||
match node {
|
||||
NodeOrToken::Node(n) => {
|
||||
let children: Vec<_> =
|
||||
n.children_with_tokens().map(|it| node_to_json(it, line_index)).collect();
|
||||
JsonNode {
|
||||
kind,
|
||||
node_type: "Node",
|
||||
start: pos(line_index, range.start()),
|
||||
end: pos(line_index, range.end()),
|
||||
text: None,
|
||||
children: Some(children),
|
||||
}
|
||||
}
|
||||
NodeOrToken::Token(t) => JsonNode {
|
||||
kind,
|
||||
node_type: "Token",
|
||||
start: pos(line_index, range.start()),
|
||||
end: pos(line_index, range.end()),
|
||||
text: Some(t.text().to_owned()),
|
||||
children: None,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::cli::flags;
|
||||
|
||||
#[test]
|
||||
fn test_parse_json_output() {
|
||||
let text = "fn main() {}".to_owned();
|
||||
let flags = flags::Parse { json: true, no_dump: false };
|
||||
let line_index = LineIndex::new(&text);
|
||||
|
||||
let file = SourceFile::parse(&text, Edition::CURRENT).tree();
|
||||
|
||||
let output = if flags.json {
|
||||
let json_tree = node_to_json(NodeOrToken::Node(file.syntax().clone()), &line_index);
|
||||
serde_json::to_string(&json_tree).unwrap()
|
||||
} else {
|
||||
format!("{:#?}", file.syntax())
|
||||
};
|
||||
|
||||
assert!(output.contains(r#""kind":"SOURCE_FILE""#));
|
||||
assert!(output.contains(r#""text":"main""#));
|
||||
assert!(output.contains(r#""start":[0,0,0]"#));
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user