Skip to content
This repository was archived by the owner on Apr 23, 2026. It is now read-only.

Commit 002cd4b

Browse files
authored
[json] include file envelope (#7)
1 parent 52a5c92 commit 002cd4b

1 file changed

Lines changed: 104 additions & 31 deletions

File tree

src/json_gen.rs

Lines changed: 104 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,49 +1,105 @@
1-
use crate::{cargo, config, json_gen};
1+
use crate::{cargo, config};
22
use anyhow::Context;
33
use log::{error, info};
44
use ra_ap_hir::{Semantics, attach_db};
55
use ra_ap_ide::{Analysis, AnalysisHost, LineIndex, RootDatabase};
6-
use ra_ap_syntax::{AstNode, SyntaxNode};
6+
use ra_ap_syntax::{AstNode, NodeOrToken, SyntaxNode, SyntaxToken};
77
use ra_ap_vfs::{FileId, VfsPath};
88
use serde::Serialize;
99
use std::path::Path;
1010

11+
/// Per-file envelope wrapping the AST.
12+
#[derive(Serialize)]
13+
#[serde(rename_all = "camelCase")]
14+
pub(crate) struct RustAstGenJsonFile {
15+
pub(crate) relative_file_path: String,
16+
pub(crate) full_file_path: String,
17+
pub(crate) content: String,
18+
pub(crate) loc: u32,
19+
pub(crate) children: Vec<RustAstGenJsonNode>,
20+
}
21+
22+
/// A single node or token in the AST.
1123
#[derive(Serialize)]
1224
#[serde(rename_all = "camelCase")]
1325
pub(crate) struct RustAstGenJsonNode {
1426
pub(crate) node_kind: String,
27+
pub(crate) range: RustAstGenJsonNodeRange,
28+
pub(crate) children: Vec<RustAstGenJsonNode>,
29+
}
30+
31+
/// Source location range for a node/token.
32+
#[derive(Serialize)]
33+
#[serde(rename_all = "camelCase")]
34+
pub(crate) struct RustAstGenJsonNodeRange {
1535
pub(crate) start_offset: u32,
1636
pub(crate) end_offset: u32,
1737
pub(crate) start_line: u32,
1838
pub(crate) start_column: u32,
19-
pub(crate) children: Vec<RustAstGenJsonNode>,
2039
}
2140

22-
pub(crate) fn make_json_node(node: &SyntaxNode, line_index: &LineIndex) -> RustAstGenJsonNode {
23-
let node_kind = format!("{:?}", node.kind());
24-
25-
// Note, LineIndex is 0-based (in both line and column)
26-
let text_range = node.text_range();
27-
let start = text_range.start();
28-
let end = text_range.end();
29-
let start_line_col = line_index.line_col(start);
30-
let start_line = start_line_col.line;
31-
let start_column = start_line_col.col;
32-
let start_offset = u32::from(start);
33-
let end_offset = u32::from(end);
34-
35-
let children = node
36-
.children()
37-
.map(|child| make_json_node(&child, &line_index))
38-
.collect::<Vec<RustAstGenJsonNode>>();
39-
40-
RustAstGenJsonNode {
41-
node_kind,
42-
start_offset,
43-
end_offset,
44-
start_line,
45-
start_column,
46-
children,
41+
impl RustAstGenJsonNodeRange {
42+
pub(crate) fn from_node(node: &SyntaxNode, line_index: &LineIndex) -> Self {
43+
let text_range = node.text_range();
44+
let start = text_range.start();
45+
let end = text_range.end();
46+
let start_line_col = line_index.line_col(start);
47+
48+
Self {
49+
start_offset: u32::from(start),
50+
end_offset: u32::from(end),
51+
start_line: start_line_col.line,
52+
start_column: start_line_col.col,
53+
}
54+
}
55+
56+
pub(crate) fn from_token(token: &SyntaxToken, line_index: &LineIndex) -> Self {
57+
let text_range = token.text_range();
58+
let start = text_range.start();
59+
let end = text_range.end();
60+
let start_line_col = line_index.line_col(start);
61+
62+
Self {
63+
start_offset: u32::from(start),
64+
end_offset: u32::from(end),
65+
start_line: start_line_col.line,
66+
start_column: start_line_col.col,
67+
}
68+
}
69+
}
70+
71+
impl RustAstGenJsonNode {
72+
pub(crate) fn from_node(node: &SyntaxNode, line_index: &LineIndex) -> Self {
73+
let node_kind = format!("{:?}", node.kind());
74+
let range = RustAstGenJsonNodeRange::from_node(node, line_index);
75+
let children = node
76+
.children_with_tokens()
77+
.filter(|child| !child.kind().is_trivia())
78+
.map(|node_or_token| match node_or_token {
79+
NodeOrToken::Node(child_node) => Self::from_node(&child_node, line_index),
80+
NodeOrToken::Token(child_token) => {
81+
RustAstGenJsonNode::from_token(&child_token, line_index)
82+
}
83+
})
84+
.collect();
85+
86+
Self {
87+
node_kind,
88+
range,
89+
children,
90+
}
91+
}
92+
93+
pub(crate) fn from_token(token: &SyntaxToken, line_index: &LineIndex) -> Self {
94+
let node_kind = format!("{:?}", token.kind());
95+
let range = RustAstGenJsonNodeRange::from_token(token, line_index);
96+
let children = vec![];
97+
98+
Self {
99+
node_kind,
100+
range,
101+
children,
102+
}
47103
}
48104
}
49105

@@ -111,13 +167,30 @@ fn process_file(
111167

112168
info!("building the JSON tree: {}", input_file_path.display());
113169

114-
let rust_ast_gen_json_node = json_gen::make_json_node(&syntax_tree, &file_line_index);
170+
let json_root = RustAstGenJsonNode::from_node(&syntax_tree, &file_line_index);
171+
let contents = syntax_tree.text().to_string();
172+
let loc = file_line_index
173+
.line_col(syntax_tree.text_range().end())
174+
.line;
175+
// TODO: we already have similar in config. Refactor
176+
let relative_path = input_file_path
177+
.strip_prefix(&config.input_dir_full_path)
178+
.with_context(|| format!("failed to strip prefix: {:?}", input_file_path))?;
179+
180+
let envelope = RustAstGenJsonFile {
181+
relative_file_path: relative_path.to_string_lossy().to_string(),
182+
full_file_path: input_file_path.to_string_lossy().to_string(),
183+
content: contents,
184+
loc,
185+
children: vec![json_root],
186+
};
187+
115188
let output_file = config.make_output_path_for_input_file(&input_file_path.to_path_buf())?;
116189

117190
info!("writing to: {}", output_file.display());
118191

119-
let json_tree = serde_json::to_string_pretty(&rust_ast_gen_json_node)?;
120-
json_gen::write_json_to_file(&json_tree, &output_file)?;
192+
let json_tree = serde_json::to_string_pretty(&envelope)?;
193+
write_json_to_file(&json_tree, &output_file)?;
121194

122195
Ok(())
123196
}

0 commit comments

Comments
 (0)