Add line numbers to file paths in the website editor structure docs (#3130)

* added the line number to existing path

* Update JS parser to use line numbers

---------

Co-authored-by: Keavon Chambers <keavon@keavon.com>
This commit is contained in:
Mohd Mohsin 2026-02-16 05:29:27 +05:30 committed by GitHub
parent 82f7dc7062
commit b697cc8131
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 51 additions and 14 deletions

View File

@ -49,11 +49,11 @@ pub trait HierarchicalTree {
fn build_message_tree() -> DebugMessageTree; fn build_message_tree() -> DebugMessageTree;
fn message_handler_data_str() -> MessageData { fn message_handler_data_str() -> MessageData {
MessageData::new(String::new(), Vec::new(), "") MessageData::new(String::new(), Vec::new(), "", 0)
} }
fn message_handler_str() -> MessageData { fn message_handler_str() -> MessageData {
MessageData::new(String::new(), Vec::new(), "") MessageData::new(String::new(), Vec::new(), "", 0)
} }
fn path() -> &'static str { fn path() -> &'static str {
@ -64,5 +64,6 @@ pub trait HierarchicalTree {
pub trait ExtractField { pub trait ExtractField {
fn field_types() -> Vec<(String, usize)>; fn field_types() -> Vec<(String, usize)>;
fn path() -> &'static str; fn path() -> &'static str;
fn line_number() -> usize;
fn print_field_types(); fn print_field_types();
} }

View File

@ -3,11 +3,12 @@ pub struct MessageData {
name: String, name: String,
fields: Vec<(String, usize)>, fields: Vec<(String, usize)>,
path: &'static str, path: &'static str,
line_number: usize,
} }
impl MessageData { impl MessageData {
pub fn new(name: String, fields: Vec<(String, usize)>, path: &'static str) -> MessageData { pub fn new(name: String, fields: Vec<(String, usize)>, path: &'static str, line_number: usize) -> MessageData {
MessageData { name, fields, path } MessageData { name, fields, path, line_number }
} }
pub fn name(&self) -> &str { pub fn name(&self) -> &str {
@ -21,6 +22,10 @@ impl MessageData {
pub fn path(&self) -> &'static str { pub fn path(&self) -> &'static str {
self.path self.path
} }
pub fn line_number(&self) -> usize {
self.line_number
}
} }
#[derive(Debug)] #[derive(Debug)]
@ -31,6 +36,7 @@ pub struct DebugMessageTree {
message_handler: Option<MessageData>, message_handler: Option<MessageData>,
message_handler_data: Option<MessageData>, message_handler_data: Option<MessageData>,
path: &'static str, path: &'static str,
line_number: usize,
} }
impl DebugMessageTree { impl DebugMessageTree {
@ -42,6 +48,7 @@ impl DebugMessageTree {
message_handler: None, message_handler: None,
message_handler_data: None, message_handler_data: None,
path: "", path: "",
line_number: 0,
} }
} }
@ -53,6 +60,10 @@ impl DebugMessageTree {
self.path = path; self.path = path;
} }
pub fn set_line_number(&mut self, line_number: usize) {
self.line_number = line_number
}
pub fn add_variant(&mut self, variant: DebugMessageTree) { pub fn add_variant(&mut self, variant: DebugMessageTree) {
if let Some(variants) = &mut self.variants { if let Some(variants) = &mut self.variants {
variants.push(variant); variants.push(variant);
@ -81,6 +92,10 @@ impl DebugMessageTree {
self.path self.path
} }
pub fn line_number(&self) -> usize {
self.line_number
}
pub fn variants(&self) -> Option<&Vec<DebugMessageTree>> { pub fn variants(&self) -> Option<&Vec<DebugMessageTree>> {
self.variants.as_ref() self.variants.as_ref()
} }

View File

@ -9,6 +9,8 @@ pub fn derive_extract_field_impl(input: TokenStream) -> syn::Result<TokenStream>
let generics = &input.generics; let generics = &input.generics;
let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
let line_number = struct_name.span().start().line;
let fields = match &input.data { let fields = match &input.data {
Data::Struct(data) => match &data.fields { Data::Struct(data) => match &data.fields {
Fields::Named(fields) => &fields.named, Fields::Named(fields) => &fields.named,
@ -50,6 +52,11 @@ pub fn derive_extract_field_impl(input: TokenStream) -> syn::Result<TokenStream>
fn path() -> &'static str { fn path() -> &'static str {
file!() file!()
} }
fn line_number() -> usize {
#line_number
}
} }
}; };

View File

@ -7,6 +7,8 @@ pub fn generate_hierarchical_tree(input: TokenStream) -> syn::Result<TokenStream
let input = parse2::<DeriveInput>(input)?; let input = parse2::<DeriveInput>(input)?;
let input_type = &input.ident; let input_type = &input.ident;
let line_number = input_type.span().start().line;
let data = match &input.data { let data = match &input.data {
Data::Enum(data) => data, Data::Enum(data) => data,
_ => return Err(syn::Error::new(Span::call_site(), "Tried to derive HierarchicalTree for non-enum")), _ => return Err(syn::Error::new(Span::call_site(), "Tried to derive HierarchicalTree for non-enum")),
@ -101,6 +103,8 @@ pub fn generate_hierarchical_tree(input: TokenStream) -> syn::Result<TokenStream
message_tree.set_path(file!()); message_tree.set_path(file!());
message_tree.set_line_number(#line_number);
message_tree message_tree
} }
} }

View File

@ -16,6 +16,8 @@ pub fn message_handler_data_attr_impl(attr: TokenStream, input_item: TokenStream
let input_type = path.segments.last().map(|s| &s.ident).unwrap(); let input_type = path.segments.last().map(|s| &s.ident).unwrap();
let handler_line_number = input_type.span().start().line;
// Extract the message type from the trait path // Extract the message type from the trait path
let trait_path = match &impl_block.trait_ { let trait_path = match &impl_block.trait_ {
Some((_, path, _)) => path, Some((_, path, _)) => path,
@ -40,14 +42,16 @@ pub fn message_handler_data_attr_impl(attr: TokenStream, input_item: TokenStream
// Get just the base identifier (ToolMessageData) without generics // Get just the base identifier (ToolMessageData) without generics
let type_name = &type_path.path.segments.first().unwrap().ident; let type_name = &type_path.path.segments.first().unwrap().ident;
let handler_data_line_number = type_name.span().start().line;
quote! { quote! {
#input_item #input_item
impl #message_type { impl #message_type {
pub fn message_handler_data_str() -> MessageData { pub fn message_handler_data_str() -> MessageData {
MessageData::new(format!("{}", stringify!(#type_name)), #type_name::field_types(), #type_name::path()) MessageData::new(format!("{}", stringify!(#type_name)), #type_name::field_types(), #type_name::path(), #type_name::line_number())
} }
pub fn message_handler_str() -> MessageData { pub fn message_handler_str() -> MessageData {
MessageData::new(format!("{}", stringify!(#input_type)), #input_type::field_types(), #input_type::path()) MessageData::new(format!("{}", stringify!(#input_type)), #input_type::field_types(), #input_type::path(), #input_type::line_number())
} }
} }
@ -57,7 +61,7 @@ pub fn message_handler_data_attr_impl(attr: TokenStream, input_item: TokenStream
#input_item #input_item
impl #message_type { impl #message_type {
pub fn message_handler_str() -> MessageData { pub fn message_handler_str() -> MessageData {
MessageData::new(format!("{}", stringify!(#input_type)), #input_type::field_types(), #input_type::path()) MessageData::new(format!("{}", stringify!(#input_type)), #input_type::field_types(), #input_type::path(), #input_type::line_number())
} }
} }
}, },
@ -67,16 +71,19 @@ pub fn message_handler_data_attr_impl(attr: TokenStream, input_item: TokenStream
syn::Type::Path(type_path) => &type_path.path.segments.first().unwrap().ident, syn::Type::Path(type_path) => &type_path.path.segments.first().unwrap().ident,
_ => return Err(syn::Error::new(type_reference.elem.span(), "Expected type path")), _ => return Err(syn::Error::new(type_reference.elem.span(), "Expected type path")),
}; };
let type_line_number = type_ident.span().start().line;
let tr = clean_rust_type_syntax(type_reference.to_token_stream().to_string()); let tr = clean_rust_type_syntax(type_reference.to_token_stream().to_string());
quote! { quote! {
#input_item #input_item
impl #message_type { impl #message_type {
pub fn message_handler_data_str() -> MessageData { pub fn message_handler_data_str() -> MessageData {
MessageData::new(format!("{}", #tr), #type_ident::field_types(), #type_ident::path()) MessageData::new(format!("{}", #tr), #type_ident::field_types(), #type_ident::path(), #type_ident::line_number())
} }
pub fn message_handler_str() -> MessageData { pub fn message_handler_str() -> MessageData {
MessageData::new(format!("{}", stringify!(#input_type)), #input_type::field_types(), #input_type::path()) MessageData::new(format!("{}", stringify!(#input_type)), #input_type::field_types(), #input_type::path(), #input_type::line_number())
} }
} }

View File

@ -6,7 +6,7 @@ fn main() {
let result = Message::message_tree(); let result = Message::message_tree();
std::fs::create_dir_all("../../website/generated").unwrap(); std::fs::create_dir_all("../../website/generated").unwrap();
let mut file = std::fs::File::create("../../website/generated/hierarchical_message_system_tree.txt").unwrap(); let mut file = std::fs::File::create("../../website/generated/hierarchical_message_system_tree.txt").unwrap();
file.write_all(format!("{} `{}`\n", result.name(), result.path()).as_bytes()).unwrap(); file.write_all(format!("{} `{}#L{}`\n", result.name(), result.path(), result.line_number()).as_bytes()).unwrap();
if let Some(variants) = result.variants() { if let Some(variants) = result.variants() {
for (i, variant) in variants.iter().enumerate() { for (i, variant) in variants.iter().enumerate() {
let is_last = i == variants.len() - 1; let is_last = i == variants.len() - 1;
@ -28,7 +28,8 @@ fn print_tree_node(tree: &DebugMessageTree, prefix: &str, is_last: bool, file: &
if tree.path().is_empty() { if tree.path().is_empty() {
file.write_all(format!("{}{}{}\n", prefix, branch, tree.name()).as_bytes()).unwrap(); file.write_all(format!("{}{}{}\n", prefix, branch, tree.name()).as_bytes()).unwrap();
} else { } else {
file.write_all(format!("{}{}{} `{}`\n", prefix, branch, tree.name(), tree.path()).as_bytes()).unwrap(); file.write_all(format!("{}{}{} `{}#L{}`\n", prefix, branch, tree.name(), tree.path(), tree.line_number()).as_bytes())
.unwrap();
} }
// Print children if any // Print children if any
@ -64,7 +65,8 @@ fn print_tree_node(tree: &DebugMessageTree, prefix: &str, is_last: bool, file: &
if data.name().is_empty() && tree.name() != FRONTEND_MESSAGE_STR { if data.name().is_empty() && tree.name() != FRONTEND_MESSAGE_STR {
panic!("{}'s MessageHandler is missing #[message_handler_data]", tree.name()); panic!("{}'s MessageHandler is missing #[message_handler_data]", tree.name());
} else if tree.name() != FRONTEND_MESSAGE_STR { } else if tree.name() != FRONTEND_MESSAGE_STR {
file.write_all(format!("{}{}{} `{}`\n", prefix, branch, data.name(), data.path()).as_bytes()).unwrap(); file.write_all(format!("{}{}{} `{}#L{}`\n", prefix, branch, data.name(), data.path(), data.line_number()).as_bytes())
.unwrap();
for (i, field) in data.fields().iter().enumerate() { for (i, field) in data.fields().iter().enumerate() {
let is_last_field = i == len - 1; let is_last_field = i == len - 1;
@ -81,7 +83,8 @@ fn print_tree_node(tree: &DebugMessageTree, prefix: &str, is_last: bool, file: &
if data.path().is_empty() { if data.path().is_empty() {
file.write_all(format!("{}{}{}\n", prefix, "└── ", data.name()).as_bytes()).unwrap(); file.write_all(format!("{}{}{}\n", prefix, "└── ", data.name()).as_bytes()).unwrap();
} else { } else {
file.write_all(format!("{}{}{} `{}`\n", prefix, "└── ", data.name(), data.path()).as_bytes()).unwrap(); file.write_all(format!("{}{}{} `{}#L{}`\n", prefix, "└── ", data.name(), data.path(), data.line_number()).as_bytes())
.unwrap();
} }
for (i, field) in data.fields().iter().enumerate() { for (i, field) in data.fields().iter().enumerate() {
let is_last_field = i == len - 1; let is_last_field = i == len - 1;

View File

@ -50,7 +50,7 @@ function buildHtmlList(nodes: Entry[], currentIndex: number, currentLevel: numbe
const hasDirectChildren = i + 1 < nodes.length && nodes[i + 1].level > node.level; const hasDirectChildren = i + 1 < nodes.length && nodes[i + 1].level > node.level;
const hasDeeperChildren = hasDirectChildren && i + 2 < nodes.length && nodes[i + 2].level > nodes[i + 1].level; const hasDeeperChildren = hasDirectChildren && i + 2 < nodes.length && nodes[i + 2].level > nodes[i + 1].level;
const linkHtml = node.link ? `<a href="${node.link}" target="_blank">${path.basename(node.link)}</a>` : ""; const linkHtml = node.link ? `<a href="${node.link}" target="_blank">${path.basename(node.link.split("#L").join(":"))}</a>` : "";
const fieldPieces = node.text.match(/([^:]*):(.*)/); const fieldPieces = node.text.match(/([^:]*):(.*)/);
let escapedText; let escapedText;
if (fieldPieces && fieldPieces.length === 3) { if (fieldPieces && fieldPieces.length === 3) {