Skip to content

Commit c3fc7b2

Browse files
committed
stash some doc gen
1 parent e0e3044 commit c3fc7b2

File tree

10 files changed

+696
-10
lines changed

10 files changed

+696
-10
lines changed

Cargo.lock

Lines changed: 371 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,4 +30,5 @@ percent-encoding = "2.3"
3030
flagset = "0.4.6"
3131
encoding_rs = "0.8"
3232
url = "2.5.2"
33-
smol_str = "0.3.2"
33+
smol_str = "0.3.2"
34+
tera = "1.20.0"

crates/emmylua_doc_cli/Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,5 @@ serde_json.workspace = true
1111
lsp-types.workspace = true
1212
rowan.workspace = true
1313
walkdir.workspace = true
14-
structopt.workspace = true
14+
structopt.workspace = true
15+
tera.workspace = true
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
use structopt::StructOpt;
2+
3+
#[derive(Debug, StructOpt)]
4+
pub struct CmdArgs {
5+
/// The path of the lua file
6+
#[structopt(
7+
parse(from_os_str),
8+
long = "input",
9+
short = "i",
10+
help = "The path of the lua project"
11+
)]
12+
pub input: std::path::PathBuf,
13+
/// The output path of the markdown file
14+
#[structopt(
15+
parse(from_os_str),
16+
default_value = "./output",
17+
long = "output",
18+
short = "o",
19+
help = "The output path of the markdown file"
20+
)]
21+
pub output: std::path::PathBuf,
22+
}

crates/emmylua_doc_cli/src/main.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
mod cmd_args;
12
mod init;
23
mod markdown_generator;
34

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,31 @@
1+
mod mod_gen;
2+
mod render;
3+
mod typ_gen;
4+
5+
use std::path::PathBuf;
6+
17
use code_analysis::EmmyLuaAnalysis;
8+
use tera::Tera;
29

310
#[allow(unused)]
4-
pub fn generate_markdown(analysis: &mut EmmyLuaAnalysis, output: &str) {
5-
6-
}
11+
pub fn generate_markdown(analysis: &mut EmmyLuaAnalysis, output: &PathBuf) -> Option<()> {
12+
let types_out = output.join("types");
13+
let module_out = output.join("modules");
14+
let resources = analysis.get_resource_dir()?;
15+
let tl_template = resources.join("template/**/*.tl");
16+
let tl = match Tera::new(tl_template.to_string_lossy().as_ref()) {
17+
Ok(tl) => tl,
18+
Err(e) => {
19+
eprintln!("Failed to load template: {}", e);
20+
return None;
21+
}
22+
};
23+
let db = analysis.compilation.get_db();
24+
let type_index = db.get_type_index();
25+
let types = type_index.get_all_types();
26+
for type_decl in types {
27+
typ_gen::generate_type_markdown(db, &tl, type_decl, &types_out);
28+
}
29+
30+
Some(())
31+
}

crates/emmylua_doc_cli/src/markdown_generator/mod_gen.rs

Whitespace-only changes.
Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
use code_analysis::{humanize_type, DbIndex, LuaPropertyOwnerId, LuaSignatureId, LuaType};
2+
3+
pub fn render_const_type(db: &DbIndex, typ: &LuaType) -> String {
4+
let const_value = humanize_type(db, typ);
5+
6+
match typ {
7+
LuaType::IntegerConst(_) | LuaType::DocIntergerConst(_) => {
8+
format!("integer = {}", const_value)
9+
}
10+
LuaType::FloatConst(_) => format!("number = {}", const_value),
11+
LuaType::StringConst(_) | LuaType::DocStringConst(_) => format!("string = {}", const_value),
12+
_ => const_value,
13+
}
14+
}
15+
16+
pub fn render_function_type(db: &DbIndex, typ: &LuaType, func_name: &str, is_local: bool) -> String {
17+
match typ {
18+
LuaType::Function => {
19+
format!(
20+
"{}function {}()",
21+
if is_local { "local " } else { "" },
22+
func_name
23+
)
24+
}
25+
LuaType::DocFunction(lua_func) => {
26+
let async_prev = if lua_func.is_async() { "async " } else { "" };
27+
let local_prev = if is_local { "local " } else { "" };
28+
let params = lua_func
29+
.get_params()
30+
.iter()
31+
.map(|param| {
32+
let name = param.0.clone();
33+
if let Some(ty) = &param.1 {
34+
format!("{}: {}", name, humanize_type(db, ty))
35+
} else {
36+
name.to_string()
37+
}
38+
})
39+
.collect::<Vec<_>>();
40+
41+
let rets = lua_func.get_ret();
42+
43+
let ret_strs = rets
44+
.iter()
45+
.map(|ty| humanize_type(db, ty))
46+
.collect::<Vec<_>>()
47+
.join(",");
48+
49+
let mut result = String::new();
50+
result.push_str(async_prev);
51+
result.push_str(local_prev);
52+
result.push_str("function ");
53+
result.push_str(func_name);
54+
result.push_str("(");
55+
if params.len() > 1 {
56+
result.push_str("\n");
57+
for param in &params {
58+
result.push_str(" ");
59+
result.push_str(param);
60+
result.push_str(",\n");
61+
}
62+
result.pop(); // Remove the last comma
63+
result.pop(); // Remove the last newline
64+
result.push_str("\n");
65+
} else {
66+
result.push_str(&params.join(", "));
67+
}
68+
result.push_str(")");
69+
if ret_strs.len() > 15 {
70+
result.push_str("\n");
71+
}
72+
73+
if !ret_strs.is_empty() {
74+
result.push_str("-> ");
75+
result.push_str(&ret_strs);
76+
}
77+
78+
result
79+
}
80+
LuaType::Signature(signature_id) => {
81+
render_signature_type(db, signature_id.clone(), func_name, is_local).unwrap_or(format!(
82+
"{}function {}",
83+
if is_local { "local " } else { "" },
84+
func_name
85+
))
86+
}
87+
_ => format!(
88+
"{}function {}",
89+
if is_local { "local " } else { "" },
90+
func_name
91+
),
92+
}
93+
}
94+
95+
fn render_signature_type(
96+
db: &DbIndex,
97+
signature_id: LuaSignatureId,
98+
func_name: &str,
99+
is_local: bool,
100+
) -> Option<String> {
101+
let signature = db.get_signature_index().get(&signature_id)?;
102+
let mut async_prev = "";
103+
if let Some(property) = db
104+
.get_property_index()
105+
.get_property(LuaPropertyOwnerId::Signature(signature_id))
106+
{
107+
async_prev = if property.is_async { "async " } else { "" };
108+
}
109+
110+
let local_prev = if is_local { "local " } else { "" };
111+
let params = signature
112+
.get_type_params()
113+
.iter()
114+
.map(|param| {
115+
let name = param.0.clone();
116+
if let Some(ty) = &param.1 {
117+
format!("{}: {}", name, humanize_type(db, ty))
118+
} else {
119+
name.to_string()
120+
}
121+
})
122+
.collect::<Vec<_>>();
123+
124+
let rets = &signature.return_docs;
125+
126+
let mut result = String::new();
127+
result.push_str(async_prev);
128+
result.push_str(local_prev);
129+
result.push_str("function ");
130+
result.push_str(func_name);
131+
result.push_str("(");
132+
if params.len() > 1 {
133+
result.push_str("\n");
134+
for param in &params {
135+
result.push_str(" ");
136+
result.push_str(param);
137+
result.push_str(",\n");
138+
}
139+
result.pop(); // Remove the last comma
140+
result.pop(); // Remove the last newline
141+
result.push_str("\n");
142+
} else {
143+
result.push_str(&params.join(", "));
144+
}
145+
result.push_str(")");
146+
match rets.len() {
147+
0 => {}
148+
1 => {
149+
result.push_str(" -> ");
150+
let type_text = humanize_type(db, &rets[0].type_ref);
151+
let name = rets[0].name.clone().unwrap_or("".to_string());
152+
let detail = if rets[0].description.is_some() {
153+
format!(" -- {}", rets[0].description.as_ref().unwrap())
154+
} else {
155+
"".to_string()
156+
};
157+
result.push_str(format!("{}{}{}", name, type_text, detail).as_str());
158+
}
159+
_ => {
160+
result.push_str("\n");
161+
for ret in rets {
162+
let type_text = humanize_type(db, &ret.type_ref);
163+
let name = ret.name.clone().unwrap_or("".to_string());
164+
let detail = if ret.description.is_some() {
165+
format!(" -- {}", ret.description.as_ref().unwrap())
166+
} else {
167+
"".to_string()
168+
};
169+
result.push_str(format!(" -> {}{}{}\n", name, type_text, detail).as_str());
170+
}
171+
}
172+
}
173+
174+
Some(result)
175+
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
use std::path::Path;
2+
3+
use code_analysis::{humanize_type, DbIndex, LuaMemberOwner, LuaPropertyOwnerId, LuaTypeDecl};
4+
use serde::{Deserialize, Serialize};
5+
use tera::Tera;
6+
7+
pub fn generate_type_markdown(
8+
db: &DbIndex,
9+
tl: &Tera,
10+
typ: &LuaTypeDecl,
11+
output: &Path,
12+
) -> Option<()> {
13+
let mut context = tera::Context::new();
14+
let typ_name = typ.get_name();
15+
context.insert("type_name", &typ_name);
16+
17+
let typ_id = typ.get_id();
18+
let namespace = typ.get_namespace();
19+
context.insert("namespace", &namespace);
20+
21+
let type_property_id = LuaPropertyOwnerId::TypeDecl(typ_id.clone());
22+
let typ_property = db.get_property_index().get_property(type_property_id);
23+
if let Some(typ_property) = typ_property {
24+
if let Some(property_text) = &typ_property.description {
25+
context.insert("description", &property_text);
26+
}
27+
}
28+
29+
let supers = db.get_type_index().get_super_types(&typ_id);
30+
if let Some(supers) = supers {
31+
let mut super_type_texts = Vec::new();
32+
for super_typ in supers {
33+
let super_type_text = humanize_type(db, &super_typ);
34+
super_type_texts.push(super_type_text);
35+
}
36+
context.insert("super_types", &super_type_texts.join(", "));
37+
}
38+
39+
let member_owner = LuaMemberOwner::Type(typ_id);
40+
let member_map = db.get_member_index().get_member_map(member_owner);
41+
let mut method_members: Vec<MethodMember> = Vec::new();
42+
let mut field_members: Vec<FieldMember> = Vec::new();
43+
if let Some(member_map) = member_map {
44+
for (member_name, member_id) in member_map {
45+
let member = db.get_member_index().get_member(member_id)?;
46+
let member_typ = member.get_decl_type();
47+
}
48+
}
49+
context.insert("methods", &method_members);
50+
context.insert("fields", &field_members);
51+
// let markdown
52+
53+
let render_text = tl.render("lua_type_template.tl", &context).ok()?;
54+
let outpath = output.join(format!("{}.md", typ.get_full_name()));
55+
std::fs::write(outpath, render_text).ok()?;
56+
Some(())
57+
}
58+
59+
#[derive(Debug, Serialize, Deserialize)]
60+
struct MethodMember {
61+
pub display_name: String,
62+
pub description: String,
63+
}
64+
65+
#[derive(Debug, Serialize, Deserialize)]
66+
struct FieldMember {
67+
pub display_name: String,
68+
pub description: String,
69+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# {{ type_name }}
2+
3+
- supers: {{ super_types }}
4+
- namespace: {{ namespace }}
5+
6+
{% if description %}
7+
{{ description }}
8+
{% endif %}
9+
10+
## methods
11+
{% for method in methods %}
12+
<span style="font-family: monospace;">`{{ method.display }}`</span>
13+
14+
{% if method.description %}
15+
<span style="margin-left: 20px; font-size: 0.9em;">{{ method.description }}</span>
16+
{% endif %}
17+
{% endfor %}
18+
19+
## fields
20+
{% for field in fields %}
21+
<span style="font-family: monospace;">`{{ field.display }}`</span>
22+
23+
{% if field.description %}
24+
<span style="margin-left: 20px; font-size: 0.9em;">{{ field.description }}</span>
25+
{% endif %}
26+
{% endfor %}

0 commit comments

Comments
 (0)