Compare commits
6 commits
a53a8f1cb4
...
bc2c0d5d2c
Author | SHA1 | Date | |
---|---|---|---|
outfoxxed | bc2c0d5d2c | ||
outfoxxed | 52514ee9fb | ||
outfoxxed | 34f0819a76 | ||
outfoxxed | 593634eb27 | ||
outfoxxed | 997eb9e876 | ||
outfoxxed | b78b75f006 |
14
flake.lock
14
flake.lock
|
@ -2,11 +2,11 @@
|
|||
"nodes": {
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1714253743,
|
||||
"narHash": "sha256-mdTQw2XlariysyScCv2tTE45QSU9v/ezLcHJ22f0Nxc=",
|
||||
"lastModified": 1730785428,
|
||||
"narHash": "sha256-Zwl8YgTVJTEum+L+0zVAWvXAGbWAuXHax3KzuejaDyo=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "58a1abdbae3217ca6b702f03d3b35125d88a2994",
|
||||
"rev": "4aa36568d413aca0ea84a1684d2d46f55dbabad7",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
@ -22,11 +22,11 @@
|
|||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1727168378,
|
||||
"narHash": "sha256-BvJuLTdqkKKzeVL8txVOTEUNWxZ1dfVdo02NdZUV+nU=",
|
||||
"lastModified": 1730842284,
|
||||
"narHash": "sha256-s0doicDkqzCqHvplBnjWPJtGJwajjDdfVkmmPu32l6Q=",
|
||||
"ref": "refs/heads/master",
|
||||
"rev": "fbaec141c01e8b3376850bd98aabeadf9fad0fcf",
|
||||
"revCount": 351,
|
||||
"rev": "b528be94260b572919ff47d2f5e3150ebc1ee3e9",
|
||||
"revCount": 368,
|
||||
"type": "git",
|
||||
"url": "https://git.outfoxxed.me/outfoxxed/quickshell"
|
||||
},
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
nixpkgs.url = "nixpkgs/nixos-unstable";
|
||||
|
||||
quickshell = {
|
||||
url = "git+https://git.outfoxxed.me/outfoxxed/quickshell";
|
||||
url = "git+https://git.outfoxxed.me/quickshell/quickshell";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
};
|
||||
|
@ -19,6 +19,10 @@
|
|||
srcpath = "${quickshell}/src";
|
||||
};
|
||||
|
||||
quickshell-types = pkgs.callPackage ./types.nix {
|
||||
srcpath = "${quickshell}/src";
|
||||
};
|
||||
|
||||
default = quickshell-docs;
|
||||
});
|
||||
};
|
||||
|
|
|
@ -4,6 +4,7 @@ use anyhow::{anyhow, Context};
|
|||
|
||||
mod outform;
|
||||
mod parse;
|
||||
mod reformat;
|
||||
mod resolver;
|
||||
mod typespec;
|
||||
|
||||
|
@ -133,6 +134,7 @@ hidetitle = true
|
|||
}
|
||||
|
||||
let index = outform::ModuleIndex {
|
||||
name: module.header.name.to_string(),
|
||||
description: module.header.description,
|
||||
details: module.details.to_string(),
|
||||
};
|
||||
|
|
|
@ -4,14 +4,23 @@ use serde::Serialize;
|
|||
|
||||
#[derive(Debug, Serialize)]
|
||||
pub struct ModuleIndex {
|
||||
pub name: String,
|
||||
pub description: String,
|
||||
pub details: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
pub struct TypeInfo {
|
||||
pub name: String,
|
||||
pub module: String,
|
||||
#[serde(flatten)]
|
||||
pub details: TypeDetails,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
#[serde(tag = "type")]
|
||||
pub enum TypeInfo {
|
||||
pub enum TypeDetails {
|
||||
Class(ClassInfo),
|
||||
Enum(EnumInfo),
|
||||
}
|
||||
|
|
|
@ -4,7 +4,10 @@ use anyhow::{anyhow, bail, Context};
|
|||
use fancy_regex::Regex;
|
||||
use serde::Deserialize;
|
||||
|
||||
use crate::typespec;
|
||||
use crate::{
|
||||
reformat::{self, ReformatPass},
|
||||
typespec,
|
||||
};
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
pub struct ModuleInfoHeader {
|
||||
|
@ -751,7 +754,6 @@ impl From<InvokableParam<'_>> for typespec::FnParam {
|
|||
|
||||
fn parse_details(comment: Comment) -> String {
|
||||
let mut seen_content = false;
|
||||
let mut callout = false;
|
||||
|
||||
let mut str = comment
|
||||
.text
|
||||
|
@ -768,127 +770,14 @@ fn parse_details(comment: Comment) -> String {
|
|||
seen_content |= any;
|
||||
filter
|
||||
})
|
||||
.map(|line| match callout {
|
||||
true => {
|
||||
if line.starts_with('>') {
|
||||
Cow::Borrowed(line[1..].strip_prefix(' ').unwrap_or(&line[1..]))
|
||||
} else {
|
||||
callout = false;
|
||||
Cow::Owned(format!("{{{{< /callout >}}}}\n{line}"))
|
||||
}
|
||||
},
|
||||
false => {
|
||||
if line.starts_with("> [!") {
|
||||
let code = line[4..].split_once(']');
|
||||
|
||||
if let Some((code, line)) = code {
|
||||
let code = code.to_lowercase();
|
||||
callout = true;
|
||||
return Cow::Owned(format!("{{{{< callout type=\"{code}\" >}}}}\n{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 separators = [
|
||||
('$', true),
|
||||
(' ', false),
|
||||
(',', false),
|
||||
(';', false),
|
||||
(':', false),
|
||||
];
|
||||
|
||||
let (mut end, mut ty) = src.chars().enumerate()
|
||||
.find_map(|(i, char)| {
|
||||
separators.iter()
|
||||
.find(|(sc, _)| char == *sc)
|
||||
.map(|(_, strip)| (i + if *strip { 1 } else { 0 }, &src[..i]))
|
||||
})
|
||||
.unwrap_or_else(|| (src.len(), src));
|
||||
|
||||
// special case for . as it is contained in valid types as well
|
||||
if ty.ends_with('.') {
|
||||
end -= 1;
|
||||
ty = &ty[..ty.len() - 1];
|
||||
}
|
||||
|
||||
let (ty, member) = match ty.chars().next() {
|
||||
None => (None, None),
|
||||
Some(c) if c.is_lowercase() => (None, Some(ty)),
|
||||
Some(_) => {
|
||||
let mut split = ty.rsplit_once('.').unwrap_or(("", ty));
|
||||
|
||||
let member = 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;
|
||||
}
|
||||
|
||||
(Some((module, name)), Some(member))
|
||||
},
|
||||
};
|
||||
|
||||
let (membertype, membername) = match member {
|
||||
None => ("", ""),
|
||||
Some(name) if name.ends_with("()") => ("func", &name[..name.len() - 2]),
|
||||
Some(name) if name.ends_with("(s)") => ("signal", &name[..name.len() - 3]),
|
||||
Some(name) if name.is_empty() => ("", ""),
|
||||
Some(name) => ("prop", name),
|
||||
};
|
||||
|
||||
let ((linktype, module), name) = match ty {
|
||||
Some((module, name)) => {
|
||||
let module = match module {
|
||||
module if module.starts_with("Quickshell") => ("local", module.to_string()),
|
||||
module => ("qt", format!("qml.{module}")),
|
||||
};
|
||||
|
||||
(module, name)
|
||||
},
|
||||
None => (("", String::new()), ""),
|
||||
};
|
||||
|
||||
accum += &format!(
|
||||
r#"{{{{< qmltypelink type="{linktype}" module="{module}" name="{name}" mtype="{membertype}" mname="{membername}" >}}}}"#
|
||||
);
|
||||
src = &src[end..];
|
||||
}
|
||||
|
||||
accum += src;
|
||||
|
||||
return Cow::Owned(accum);
|
||||
} else {
|
||||
return line;
|
||||
}
|
||||
})
|
||||
.fold(String::new(), |accum, line| accum + line.as_ref() + "\n");
|
||||
|
||||
if callout {
|
||||
str += "\n{{< /callout >}}";
|
||||
}
|
||||
let reformat_ctx = reformat::Context {
|
||||
module: comment.module,
|
||||
};
|
||||
|
||||
crate::reformat::GfmQuoteBlocks::new().reformat(&reformat_ctx, &mut str);
|
||||
crate::reformat::TypeLinks.reformat(&reformat_ctx, &mut str);
|
||||
|
||||
str
|
||||
}
|
||||
|
|
140
typegen/src/reformat.rs
Normal file
140
typegen/src/reformat.rs
Normal file
|
@ -0,0 +1,140 @@
|
|||
use std::borrow::Cow;
|
||||
|
||||
use fancy_regex::Regex;
|
||||
|
||||
pub struct Context<'a> {
|
||||
pub module: &'a str,
|
||||
}
|
||||
|
||||
pub trait ReformatPass {
|
||||
fn reformat(&self, context: &Context, text: &mut String);
|
||||
}
|
||||
|
||||
pub struct GfmQuoteBlocks {
|
||||
callout_regex: Regex,
|
||||
}
|
||||
|
||||
impl GfmQuoteBlocks {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
callout_regex: Regex::new(r#">\s+\[!(?<type>\w+)]\s+(?=\w)"#).unwrap()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ReformatPass for GfmQuoteBlocks {
|
||||
fn reformat(&self, _: &Context, text: &mut String) {
|
||||
*text = text.replace("> [!INFO]", "> [!NOTE]");
|
||||
*text = self.callout_regex.replace_all(text, "> [!$type]\n> ").to_string();
|
||||
}
|
||||
}
|
||||
|
||||
pub struct TypeLinks;
|
||||
|
||||
impl ReformatPass for TypeLinks {
|
||||
fn reformat(&self ,context: &Context, text: &mut String) {
|
||||
let lines = text.lines().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 separators = [
|
||||
('$', true),
|
||||
(' ', false),
|
||||
(',', false),
|
||||
(';', false),
|
||||
(':', false),
|
||||
];
|
||||
|
||||
let (mut end, mut ty) = src
|
||||
.chars()
|
||||
.enumerate()
|
||||
.find_map(|(i, char)| {
|
||||
separators
|
||||
.iter()
|
||||
.find(|(sc, _)| char == *sc)
|
||||
.map(|(_, strip)| (i + if *strip { 1 } else { 0 }, &src[..i]))
|
||||
})
|
||||
.unwrap_or_else(|| (src.len(), src));
|
||||
|
||||
// special case for . as it is contained in valid types as well
|
||||
if ty.ends_with('.') {
|
||||
end -= 1;
|
||||
ty = &ty[..ty.len() - 1];
|
||||
}
|
||||
|
||||
let (ty, member) = match ty.chars().next() {
|
||||
None => (None, None),
|
||||
Some(c) if c.is_lowercase() => (None, Some(ty)),
|
||||
Some(_) => {
|
||||
let mut split = ty.rsplit_once('.').unwrap_or(("", ty));
|
||||
|
||||
let member = 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 = context.module;
|
||||
}
|
||||
|
||||
(Some((module, name)), Some(member))
|
||||
},
|
||||
};
|
||||
|
||||
let (membertype, membername) = match member {
|
||||
None => ("", ""),
|
||||
Some(name) if name.ends_with("()") => ("func", &name[..name.len() - 2]),
|
||||
Some(name) if name.ends_with("(s)") => ("signal", &name[..name.len() - 3]),
|
||||
Some(name) if name.is_empty() => ("", ""),
|
||||
Some(name) => ("prop", name),
|
||||
};
|
||||
|
||||
accum += "TYPE";
|
||||
|
||||
if let Some((module, name)) = ty {
|
||||
if module.starts_with("Quickshell") {
|
||||
accum += "99MQS";
|
||||
} else {
|
||||
accum += "99MQT_qml";
|
||||
}
|
||||
|
||||
accum = module
|
||||
.split('.')
|
||||
.fold(accum, |accum, next| accum + "_" + next)
|
||||
+ "99N" + name;
|
||||
}
|
||||
|
||||
if !membername.is_empty() {
|
||||
accum += &format!("99V{membername}99T{membertype}");
|
||||
}
|
||||
|
||||
accum += "99TYPE";
|
||||
src = &src[end..];
|
||||
}
|
||||
|
||||
accum += src;
|
||||
|
||||
return Cow::Owned(accum);
|
||||
} else {
|
||||
return Cow::Borrowed(line);
|
||||
}
|
||||
});
|
||||
|
||||
*text = lines.fold(String::new(), |accum, line| accum + line.as_ref() + "\n");
|
||||
}
|
||||
}
|
|
@ -235,37 +235,42 @@ pub fn resolve_types(
|
|||
None => HashMap::new(),
|
||||
};
|
||||
|
||||
let type_ = outform::ClassInfo {
|
||||
superclass,
|
||||
description: class.description.clone(),
|
||||
details: class.details.clone(),
|
||||
flags: {
|
||||
let mut flags = Vec::new();
|
||||
let type_ = outform::TypeInfo {
|
||||
name: mapping.name.clone(),
|
||||
module: mapping.module.clone().unwrap(),
|
||||
details: outform::TypeDetails::Class(outform::ClassInfo {
|
||||
superclass,
|
||||
description: class.description.clone(),
|
||||
details: class.details.clone(),
|
||||
flags: {
|
||||
let mut flags = Vec::new();
|
||||
|
||||
if coreenum.is_some() {
|
||||
flags.push(Flag::Enum);
|
||||
} else if class.singleton {
|
||||
flags.push(Flag::Singleton);
|
||||
} else if class.uncreatable {
|
||||
flags.push(Flag::Uncreatable);
|
||||
}
|
||||
if coreenum.is_some() {
|
||||
flags.push(Flag::Enum);
|
||||
} else if class.singleton {
|
||||
flags.push(Flag::Singleton);
|
||||
} else if class.uncreatable {
|
||||
flags.push(Flag::Uncreatable);
|
||||
}
|
||||
|
||||
flags
|
||||
},
|
||||
properties,
|
||||
functions,
|
||||
signals,
|
||||
variants,
|
||||
flags
|
||||
},
|
||||
properties,
|
||||
functions,
|
||||
signals,
|
||||
variants,
|
||||
}),
|
||||
};
|
||||
|
||||
outtypes.insert(mapping.name.clone(), outform::TypeInfo::Class(type_));
|
||||
outtypes.insert(mapping.name.clone(), type_);
|
||||
}
|
||||
|
||||
for enum_ in typespec.enums {
|
||||
if enum_.module.as_ref().map(|v| v as &str) == Some(module) {
|
||||
outtypes.insert(
|
||||
enum_.name,
|
||||
outform::TypeInfo::Enum(outform::EnumInfo {
|
||||
outtypes.insert(enum_.name.clone(), outform::TypeInfo {
|
||||
name: enum_.name,
|
||||
module: enum_.module.unwrap(),
|
||||
details: outform::TypeDetails::Enum(outform::EnumInfo {
|
||||
description: enum_.description,
|
||||
details: enum_.details,
|
||||
variants: enum_
|
||||
|
@ -278,7 +283,7 @@ pub fn resolve_types(
|
|||
})
|
||||
.collect(),
|
||||
}),
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
23
types.nix
Normal file
23
types.nix
Normal file
|
@ -0,0 +1,23 @@
|
|||
{
|
||||
stdenv,
|
||||
nix-gitignore,
|
||||
just,
|
||||
|
||||
callPackage,
|
||||
typegen ? (callPackage ./typegen {}),
|
||||
srcpath ? ../src,
|
||||
}: stdenv.mkDerivation {
|
||||
name = "quickshell-types";
|
||||
version = "0.1.0";
|
||||
src = nix-gitignore.gitignoreSource "/typegen\n" ./.;
|
||||
|
||||
buildInputs = [ just typegen ];
|
||||
|
||||
buildPhase = ''
|
||||
SRC_PATH="${srcpath}" TYPEGEN=typegen just typedocs
|
||||
'';
|
||||
|
||||
installPhase = ''
|
||||
mv ./data/modules $out
|
||||
'';
|
||||
}
|
Loading…
Reference in a new issue