typegen: add shorthand for type/property links
This commit is contained in:
		
							parent
							
								
									11ff70f1a8
								
							
						
					
					
						commit
						db5c3aa3f4
					
				
					 3 changed files with 115 additions and 24 deletions
				
			
		| 
						 | 
					@ -13,5 +13,16 @@
 | 
				
			||||||
		{{- $of = printf "<%s>" (partial "qmltype.html" .of) }}
 | 
							{{- $of = printf "<%s>" (partial "qmltype.html" .of) }}
 | 
				
			||||||
	{{- end -}}
 | 
						{{- end -}}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	<a href="{{ $link }}">{{ .name }}</a>{{ $of | safeHTML -}}
 | 
						{{- $member := "" -}}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						{{- if .prop -}}
 | 
				
			||||||
 | 
							{{- $member = printf ".%s" .prop -}}
 | 
				
			||||||
 | 
							{{- if eq .type "qt" -}}
 | 
				
			||||||
 | 
								{{- $link = printf "%s#%s-prop" $link .prop -}}
 | 
				
			||||||
 | 
							{{- else if eq .type "local" -}}
 | 
				
			||||||
 | 
								{{- $link = printf "%s#prop.%s" $link .prop -}}
 | 
				
			||||||
 | 
							{{- end -}}
 | 
				
			||||||
 | 
						{{- end -}}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						<a href="{{ $link }}">{{ .name }}{{ $member }}</a>{{ $of | safeHTML -}}
 | 
				
			||||||
{{- end -}}
 | 
					{{- end -}}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -36,7 +36,8 @@ fn main() -> anyhow::Result<()> {
 | 
				
			||||||
				.collect::<Result<HashMap<_, _>, _>>()?;
 | 
									.collect::<Result<HashMap<_, _>, _>>()?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			let parser = parse::Parser::new();
 | 
								let parser = parse::Parser::new();
 | 
				
			||||||
			let mut ctx = parse::ParseContext::default();
 | 
								let mut ctx = parse::ParseContext::new(&module.header.name);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			texts
 | 
								texts
 | 
				
			||||||
				.iter()
 | 
									.iter()
 | 
				
			||||||
				.map(|(header, text)| {
 | 
									.map(|(header, text)| {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -33,6 +33,18 @@ pub fn parse_module(text: &str) -> anyhow::Result<ModuleInfo> {
 | 
				
			||||||
	Ok(ModuleInfo { header, details })
 | 
						Ok(ModuleInfo { header, details })
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Debug, Clone, Copy)]
 | 
				
			||||||
 | 
					pub struct Comment<'a> {
 | 
				
			||||||
 | 
						pub text: &'a str,
 | 
				
			||||||
 | 
						pub module: &'a str,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl<'a> Comment<'a> {
 | 
				
			||||||
 | 
						fn new(text: &'a str, module: &'a str) -> Self {
 | 
				
			||||||
 | 
							Self { text, module }
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Debug)]
 | 
					#[derive(Debug)]
 | 
				
			||||||
pub struct ClassInfo<'a> {
 | 
					pub struct ClassInfo<'a> {
 | 
				
			||||||
	pub type_: ClassType,
 | 
						pub type_: ClassType,
 | 
				
			||||||
| 
						 | 
					@ -41,7 +53,7 @@ pub struct ClassInfo<'a> {
 | 
				
			||||||
	pub superclass: Option<&'a str>,
 | 
						pub superclass: Option<&'a str>,
 | 
				
			||||||
	pub singleton: bool,
 | 
						pub singleton: bool,
 | 
				
			||||||
	pub uncreatable: bool,
 | 
						pub uncreatable: bool,
 | 
				
			||||||
	pub comment: Option<&'a str>,
 | 
						pub comment: Option<Comment<'a>>,
 | 
				
			||||||
	pub properties: Vec<Property<'a>>,
 | 
						pub properties: Vec<Property<'a>>,
 | 
				
			||||||
	pub invokables: Vec<Invokable<'a>>,
 | 
						pub invokables: Vec<Invokable<'a>>,
 | 
				
			||||||
	pub signals: Vec<Signal<'a>>,
 | 
						pub signals: Vec<Signal<'a>>,
 | 
				
			||||||
| 
						 | 
					@ -58,7 +70,7 @@ pub enum ClassType {
 | 
				
			||||||
pub struct Property<'a> {
 | 
					pub struct Property<'a> {
 | 
				
			||||||
	pub type_: &'a str,
 | 
						pub type_: &'a str,
 | 
				
			||||||
	pub name: &'a str,
 | 
						pub name: &'a str,
 | 
				
			||||||
	pub comment: Option<&'a str>,
 | 
						pub comment: Option<Comment<'a>>,
 | 
				
			||||||
	pub readable: bool,
 | 
						pub readable: bool,
 | 
				
			||||||
	pub writable: bool,
 | 
						pub writable: bool,
 | 
				
			||||||
	pub default: bool,
 | 
						pub default: bool,
 | 
				
			||||||
| 
						 | 
					@ -68,14 +80,14 @@ pub struct Property<'a> {
 | 
				
			||||||
pub struct Invokable<'a> {
 | 
					pub struct Invokable<'a> {
 | 
				
			||||||
	pub name: &'a str,
 | 
						pub name: &'a str,
 | 
				
			||||||
	pub ret: &'a str,
 | 
						pub ret: &'a str,
 | 
				
			||||||
	pub comment: Option<&'a str>,
 | 
						pub comment: Option<Comment<'a>>,
 | 
				
			||||||
	pub params: Vec<InvokableParam<'a>>,
 | 
						pub params: Vec<InvokableParam<'a>>,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Debug, Clone)]
 | 
					#[derive(Debug, Clone)]
 | 
				
			||||||
pub struct Signal<'a> {
 | 
					pub struct Signal<'a> {
 | 
				
			||||||
	pub name: &'a str,
 | 
						pub name: &'a str,
 | 
				
			||||||
	pub comment: Option<&'a str>,
 | 
						pub comment: Option<Comment<'a>>,
 | 
				
			||||||
	pub params: Vec<InvokableParam<'a>>,
 | 
						pub params: Vec<InvokableParam<'a>>,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -90,14 +102,14 @@ pub struct EnumInfo<'a> {
 | 
				
			||||||
	pub namespace: &'a str,
 | 
						pub namespace: &'a str,
 | 
				
			||||||
	pub enum_name: &'a str,
 | 
						pub enum_name: &'a str,
 | 
				
			||||||
	pub qml_name: &'a str,
 | 
						pub qml_name: &'a str,
 | 
				
			||||||
	pub comment: Option<&'a str>,
 | 
						pub comment: Option<Comment<'a>>,
 | 
				
			||||||
	pub variants: Vec<Variant<'a>>,
 | 
						pub variants: Vec<Variant<'a>>,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Debug, Clone, Copy)]
 | 
					#[derive(Debug, Clone, Copy)]
 | 
				
			||||||
pub struct Variant<'a> {
 | 
					pub struct Variant<'a> {
 | 
				
			||||||
	pub name: &'a str,
 | 
						pub name: &'a str,
 | 
				
			||||||
	pub comment: Option<&'a str>,
 | 
						pub comment: Option<Comment<'a>>,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub struct Parser {
 | 
					pub struct Parser {
 | 
				
			||||||
| 
						 | 
					@ -116,13 +128,15 @@ pub struct Parser {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Debug)]
 | 
					#[derive(Debug)]
 | 
				
			||||||
pub struct ParseContext<'a> {
 | 
					pub struct ParseContext<'a> {
 | 
				
			||||||
 | 
						pub module: &'a str,
 | 
				
			||||||
	pub classes: Vec<ClassInfo<'a>>,
 | 
						pub classes: Vec<ClassInfo<'a>>,
 | 
				
			||||||
	pub enums: Vec<EnumInfo<'a>>,
 | 
						pub enums: Vec<EnumInfo<'a>>,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl Default for ParseContext<'_> {
 | 
					impl<'a> ParseContext<'a> {
 | 
				
			||||||
	fn default() -> Self {
 | 
						pub fn new(module: &'a str) -> Self {
 | 
				
			||||||
		Self {
 | 
							Self {
 | 
				
			||||||
 | 
								module,
 | 
				
			||||||
			classes: Vec::new(),
 | 
								classes: Vec::new(),
 | 
				
			||||||
			enums: Vec::new(),
 | 
								enums: Vec::new(),
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
| 
						 | 
					@ -223,7 +237,7 @@ impl Parser {
 | 
				
			||||||
								properties.push(Property {
 | 
													properties.push(Property {
 | 
				
			||||||
									type_: prop.name("type").unwrap().as_str(),
 | 
														type_: prop.name("type").unwrap().as_str(),
 | 
				
			||||||
									name: prop.name("name").unwrap().as_str(),
 | 
														name: prop.name("name").unwrap().as_str(),
 | 
				
			||||||
									comment,
 | 
														comment: comment.map(|v| Comment::new(v, ctx.module)),
 | 
				
			||||||
									readable: read || member,
 | 
														readable: read || member,
 | 
				
			||||||
									writable: !constant && (write || member),
 | 
														writable: !constant && (write || member),
 | 
				
			||||||
									default: false,
 | 
														default: false,
 | 
				
			||||||
| 
						 | 
					@ -279,7 +293,7 @@ impl Parser {
 | 
				
			||||||
					invokables.push(Invokable {
 | 
										invokables.push(Invokable {
 | 
				
			||||||
						name,
 | 
											name,
 | 
				
			||||||
						ret: type_,
 | 
											ret: type_,
 | 
				
			||||||
						comment,
 | 
											comment: comment.map(|v| Comment::new(v, ctx.module)),
 | 
				
			||||||
						params,
 | 
											params,
 | 
				
			||||||
					});
 | 
										});
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
| 
						 | 
					@ -317,7 +331,7 @@ impl Parser {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
						signals.push(Signal {
 | 
											signals.push(Signal {
 | 
				
			||||||
							name,
 | 
												name,
 | 
				
			||||||
							comment,
 | 
												comment: comment.map(|v| Comment::new(v, ctx.module)),
 | 
				
			||||||
							params,
 | 
												params,
 | 
				
			||||||
						});
 | 
											});
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
| 
						 | 
					@ -329,13 +343,13 @@ impl Parser {
 | 
				
			||||||
					let comment = enum_.name("comment").map(|m| m.as_str());
 | 
										let comment = enum_.name("comment").map(|m| m.as_str());
 | 
				
			||||||
					let enum_name = enum_.name("enum_name").unwrap().as_str();
 | 
										let enum_name = enum_.name("enum_name").unwrap().as_str();
 | 
				
			||||||
					let body = enum_.name("body").unwrap().as_str();
 | 
										let body = enum_.name("body").unwrap().as_str();
 | 
				
			||||||
					let variants = self.parse_enum_variants(body)?;
 | 
										let variants = self.parse_enum_variants(body, ctx)?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
					enums.push(EnumInfo {
 | 
										enums.push(EnumInfo {
 | 
				
			||||||
						namespace: name,
 | 
											namespace: name,
 | 
				
			||||||
						enum_name,
 | 
											enum_name,
 | 
				
			||||||
						qml_name: enum_name,
 | 
											qml_name: enum_name,
 | 
				
			||||||
						comment,
 | 
											comment: comment.map(|v| Comment::new(v, ctx.module)),
 | 
				
			||||||
						variants,
 | 
											variants,
 | 
				
			||||||
					});
 | 
										});
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
| 
						 | 
					@ -353,7 +367,7 @@ impl Parser {
 | 
				
			||||||
				superclass,
 | 
									superclass,
 | 
				
			||||||
				singleton,
 | 
									singleton,
 | 
				
			||||||
				uncreatable,
 | 
									uncreatable,
 | 
				
			||||||
				comment,
 | 
									comment: comment.map(|v| Comment::new(v, ctx.module)),
 | 
				
			||||||
				properties,
 | 
									properties,
 | 
				
			||||||
				invokables,
 | 
									invokables,
 | 
				
			||||||
				signals,
 | 
									signals,
 | 
				
			||||||
| 
						 | 
					@ -376,13 +390,13 @@ impl Parser {
 | 
				
			||||||
				.map(|m| m.as_str())
 | 
									.map(|m| m.as_str())
 | 
				
			||||||
				.unwrap_or(namespace);
 | 
									.unwrap_or(namespace);
 | 
				
			||||||
			let body = enum_.name("body").unwrap().as_str();
 | 
								let body = enum_.name("body").unwrap().as_str();
 | 
				
			||||||
			let variants = self.parse_enum_variants(body)?;
 | 
								let variants = self.parse_enum_variants(body, ctx)?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			ctx.enums.push(EnumInfo {
 | 
								ctx.enums.push(EnumInfo {
 | 
				
			||||||
				namespace,
 | 
									namespace,
 | 
				
			||||||
				enum_name,
 | 
									enum_name,
 | 
				
			||||||
				qml_name,
 | 
									qml_name,
 | 
				
			||||||
				comment,
 | 
									comment: comment.map(|v| Comment::new(v, ctx.module)),
 | 
				
			||||||
				variants,
 | 
									variants,
 | 
				
			||||||
			});
 | 
								});
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
| 
						 | 
					@ -390,7 +404,11 @@ impl Parser {
 | 
				
			||||||
		Ok(())
 | 
							Ok(())
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pub fn parse_enum_variants<'a>(&self, body: &'a str) -> anyhow::Result<Vec<Variant<'a>>> {
 | 
						pub fn parse_enum_variants<'a>(
 | 
				
			||||||
 | 
							&self,
 | 
				
			||||||
 | 
							body: &'a str,
 | 
				
			||||||
 | 
							ctx: &ParseContext<'a>,
 | 
				
			||||||
 | 
						) -> anyhow::Result<Vec<Variant<'a>>> {
 | 
				
			||||||
		let mut variants = Vec::new();
 | 
							let mut variants = Vec::new();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		for variant in self.enum_variant_regex.captures_iter(body) {
 | 
							for variant in self.enum_variant_regex.captures_iter(body) {
 | 
				
			||||||
| 
						 | 
					@ -399,7 +417,10 @@ impl Parser {
 | 
				
			||||||
			let comment = variant.name("comment").map(|m| m.as_str());
 | 
								let comment = variant.name("comment").map(|m| m.as_str());
 | 
				
			||||||
			let name = variant.name("name").unwrap().as_str();
 | 
								let name = variant.name("name").unwrap().as_str();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			variants.push(Variant { name, comment });
 | 
								variants.push(Variant {
 | 
				
			||||||
 | 
									name,
 | 
				
			||||||
 | 
									comment: comment.map(|v| Comment::new(v, ctx.module)),
 | 
				
			||||||
 | 
								});
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		Ok(variants)
 | 
							Ok(variants)
 | 
				
			||||||
| 
						 | 
					@ -575,11 +596,12 @@ impl From<InvokableParam<'_>> for typespec::FnParam {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn parse_details(text: &str) -> String {
 | 
					fn parse_details(comment: Comment) -> String {
 | 
				
			||||||
	let mut seen_content = false;
 | 
						let mut seen_content = false;
 | 
				
			||||||
	let mut callout = false;
 | 
						let mut callout = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	let mut str = text
 | 
						let mut str = comment
 | 
				
			||||||
 | 
							.text
 | 
				
			||||||
		.lines()
 | 
							.lines()
 | 
				
			||||||
		.map(|line| {
 | 
							.map(|line| {
 | 
				
			||||||
			line.trim()
 | 
								line.trim()
 | 
				
			||||||
| 
						 | 
					@ -616,6 +638,63 @@ fn parse_details(text: &str) -> String {
 | 
				
			||||||
				return Cow::Borrowed(line);
 | 
									return Cow::Borrowed(line);
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
		})
 | 
							})
 | 
				
			||||||
 | 
							.map(|line| {
 | 
				
			||||||
 | 
								if line.contains("@@") {
 | 
				
			||||||
 | 
									let mut src: &str = &*line;
 | 
				
			||||||
 | 
									let mut accum = String::new();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									while let Some(i) = src.find("@@") {
 | 
				
			||||||
 | 
										accum += &src[..i];
 | 
				
			||||||
 | 
										src = &src[i + 2..];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										let endmk = src.find('$');
 | 
				
			||||||
 | 
										let endsp = src.find(' ');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										let (end, ty) = match (endmk, endsp) {
 | 
				
			||||||
 | 
											(Some(i), _) if i < endsp.unwrap_or(usize::MAX) => (i + 1, &src[..i]),
 | 
				
			||||||
 | 
											(_, Some(i)) => (i, &src[..i]),
 | 
				
			||||||
 | 
											_ => (src.len(), src),
 | 
				
			||||||
 | 
										};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										let mut split = ty.rsplit_once('.').unwrap_or(("", ty));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										let prop = split
 | 
				
			||||||
 | 
											.1
 | 
				
			||||||
 | 
											.chars()
 | 
				
			||||||
 | 
											.next()
 | 
				
			||||||
 | 
											.unwrap()
 | 
				
			||||||
 | 
											.is_lowercase()
 | 
				
			||||||
 | 
											.then(|| {
 | 
				
			||||||
 | 
												let prop = split.1;
 | 
				
			||||||
 | 
												split = split.0.rsplit_once('.').unwrap_or(("", split.0));
 | 
				
			||||||
 | 
												prop
 | 
				
			||||||
 | 
											})
 | 
				
			||||||
 | 
											.unwrap_or("");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										let (mut module, name) = split;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										if module.is_empty() {
 | 
				
			||||||
 | 
											module = comment.module;
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										let (linktype, module) = match module.starts_with("Quickshell") {
 | 
				
			||||||
 | 
											true => ("local", module.to_string()),
 | 
				
			||||||
 | 
											false => ("qt", format!("qml.{module}")),
 | 
				
			||||||
 | 
										};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										accum += &format!(
 | 
				
			||||||
 | 
											r#"{{{{< qmltypelink type="{linktype}" module="{module}" name="{name}" prop="{prop}" >}}}}"#
 | 
				
			||||||
 | 
										);
 | 
				
			||||||
 | 
										src = &src[end..];
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									accum += src;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									return Cow::Owned(accum);
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									return line;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							})
 | 
				
			||||||
		.fold(String::new(), |accum, line| accum + line.as_ref() + "\n");
 | 
							.fold(String::new(), |accum, line| accum + line.as_ref() + "\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if callout {
 | 
						if callout {
 | 
				
			||||||
| 
						 | 
					@ -625,8 +704,8 @@ fn parse_details(text: &str) -> String {
 | 
				
			||||||
	str
 | 
						str
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn parse_details_desc(text: &str) -> (Option<String>, Option<String>) {
 | 
					fn parse_details_desc(comment: Comment) -> (Option<String>, Option<String>) {
 | 
				
			||||||
	let details = parse_details(text);
 | 
						let details = parse_details(comment);
 | 
				
			||||||
	if details.starts_with('!') {
 | 
						if details.starts_with('!') {
 | 
				
			||||||
		match details[1..].split_once('\n') {
 | 
							match details[1..].split_once('\n') {
 | 
				
			||||||
			Some((desc, details)) => (
 | 
								Some((desc, details)) => (
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue