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": {
|
"nodes": {
|
||||||
"nixpkgs": {
|
"nixpkgs": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1714253743,
|
"lastModified": 1730785428,
|
||||||
"narHash": "sha256-mdTQw2XlariysyScCv2tTE45QSU9v/ezLcHJ22f0Nxc=",
|
"narHash": "sha256-Zwl8YgTVJTEum+L+0zVAWvXAGbWAuXHax3KzuejaDyo=",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "58a1abdbae3217ca6b702f03d3b35125d88a2994",
|
"rev": "4aa36568d413aca0ea84a1684d2d46f55dbabad7",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
@ -22,11 +22,11 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1727168378,
|
"lastModified": 1730842284,
|
||||||
"narHash": "sha256-BvJuLTdqkKKzeVL8txVOTEUNWxZ1dfVdo02NdZUV+nU=",
|
"narHash": "sha256-s0doicDkqzCqHvplBnjWPJtGJwajjDdfVkmmPu32l6Q=",
|
||||||
"ref": "refs/heads/master",
|
"ref": "refs/heads/master",
|
||||||
"rev": "fbaec141c01e8b3376850bd98aabeadf9fad0fcf",
|
"rev": "b528be94260b572919ff47d2f5e3150ebc1ee3e9",
|
||||||
"revCount": 351,
|
"revCount": 368,
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://git.outfoxxed.me/outfoxxed/quickshell"
|
"url": "https://git.outfoxxed.me/outfoxxed/quickshell"
|
||||||
},
|
},
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
nixpkgs.url = "nixpkgs/nixos-unstable";
|
nixpkgs.url = "nixpkgs/nixos-unstable";
|
||||||
|
|
||||||
quickshell = {
|
quickshell = {
|
||||||
url = "git+https://git.outfoxxed.me/outfoxxed/quickshell";
|
url = "git+https://git.outfoxxed.me/quickshell/quickshell";
|
||||||
inputs.nixpkgs.follows = "nixpkgs";
|
inputs.nixpkgs.follows = "nixpkgs";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -19,6 +19,10 @@
|
||||||
srcpath = "${quickshell}/src";
|
srcpath = "${quickshell}/src";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
quickshell-types = pkgs.callPackage ./types.nix {
|
||||||
|
srcpath = "${quickshell}/src";
|
||||||
|
};
|
||||||
|
|
||||||
default = quickshell-docs;
|
default = quickshell-docs;
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
|
@ -4,6 +4,7 @@ use anyhow::{anyhow, Context};
|
||||||
|
|
||||||
mod outform;
|
mod outform;
|
||||||
mod parse;
|
mod parse;
|
||||||
|
mod reformat;
|
||||||
mod resolver;
|
mod resolver;
|
||||||
mod typespec;
|
mod typespec;
|
||||||
|
|
||||||
|
@ -133,6 +134,7 @@ hidetitle = true
|
||||||
}
|
}
|
||||||
|
|
||||||
let index = outform::ModuleIndex {
|
let index = outform::ModuleIndex {
|
||||||
|
name: module.header.name.to_string(),
|
||||||
description: module.header.description,
|
description: module.header.description,
|
||||||
details: module.details.to_string(),
|
details: module.details.to_string(),
|
||||||
};
|
};
|
||||||
|
|
|
@ -4,14 +4,23 @@ use serde::Serialize;
|
||||||
|
|
||||||
#[derive(Debug, Serialize)]
|
#[derive(Debug, Serialize)]
|
||||||
pub struct ModuleIndex {
|
pub struct ModuleIndex {
|
||||||
|
pub name: String,
|
||||||
pub description: String,
|
pub description: String,
|
||||||
pub details: String,
|
pub details: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize)]
|
||||||
|
pub struct TypeInfo {
|
||||||
|
pub name: String,
|
||||||
|
pub module: String,
|
||||||
|
#[serde(flatten)]
|
||||||
|
pub details: TypeDetails,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize)]
|
#[derive(Debug, Serialize)]
|
||||||
#[serde(rename_all = "lowercase")]
|
#[serde(rename_all = "lowercase")]
|
||||||
#[serde(tag = "type")]
|
#[serde(tag = "type")]
|
||||||
pub enum TypeInfo {
|
pub enum TypeDetails {
|
||||||
Class(ClassInfo),
|
Class(ClassInfo),
|
||||||
Enum(EnumInfo),
|
Enum(EnumInfo),
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,10 @@ use anyhow::{anyhow, bail, Context};
|
||||||
use fancy_regex::Regex;
|
use fancy_regex::Regex;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
|
||||||
use crate::typespec;
|
use crate::{
|
||||||
|
reformat::{self, ReformatPass},
|
||||||
|
typespec,
|
||||||
|
};
|
||||||
|
|
||||||
#[derive(Deserialize, Debug)]
|
#[derive(Deserialize, Debug)]
|
||||||
pub struct ModuleInfoHeader {
|
pub struct ModuleInfoHeader {
|
||||||
|
@ -751,7 +754,6 @@ impl From<InvokableParam<'_>> for typespec::FnParam {
|
||||||
|
|
||||||
fn parse_details(comment: Comment) -> String {
|
fn parse_details(comment: Comment) -> String {
|
||||||
let mut seen_content = false;
|
let mut seen_content = false;
|
||||||
let mut callout = false;
|
|
||||||
|
|
||||||
let mut str = comment
|
let mut str = comment
|
||||||
.text
|
.text
|
||||||
|
@ -768,127 +770,14 @@ fn parse_details(comment: Comment) -> String {
|
||||||
seen_content |= any;
|
seen_content |= any;
|
||||||
filter
|
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");
|
.fold(String::new(), |accum, line| accum + line.as_ref() + "\n");
|
||||||
|
|
||||||
if callout {
|
let reformat_ctx = reformat::Context {
|
||||||
str += "\n{{< /callout >}}";
|
module: comment.module,
|
||||||
}
|
};
|
||||||
|
|
||||||
|
crate::reformat::GfmQuoteBlocks::new().reformat(&reformat_ctx, &mut str);
|
||||||
|
crate::reformat::TypeLinks.reformat(&reformat_ctx, &mut str);
|
||||||
|
|
||||||
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(),
|
None => HashMap::new(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let type_ = outform::ClassInfo {
|
let type_ = outform::TypeInfo {
|
||||||
superclass,
|
name: mapping.name.clone(),
|
||||||
description: class.description.clone(),
|
module: mapping.module.clone().unwrap(),
|
||||||
details: class.details.clone(),
|
details: outform::TypeDetails::Class(outform::ClassInfo {
|
||||||
flags: {
|
superclass,
|
||||||
let mut flags = Vec::new();
|
description: class.description.clone(),
|
||||||
|
details: class.details.clone(),
|
||||||
|
flags: {
|
||||||
|
let mut flags = Vec::new();
|
||||||
|
|
||||||
if coreenum.is_some() {
|
if coreenum.is_some() {
|
||||||
flags.push(Flag::Enum);
|
flags.push(Flag::Enum);
|
||||||
} else if class.singleton {
|
} else if class.singleton {
|
||||||
flags.push(Flag::Singleton);
|
flags.push(Flag::Singleton);
|
||||||
} else if class.uncreatable {
|
} else if class.uncreatable {
|
||||||
flags.push(Flag::Uncreatable);
|
flags.push(Flag::Uncreatable);
|
||||||
}
|
}
|
||||||
|
|
||||||
flags
|
flags
|
||||||
},
|
},
|
||||||
properties,
|
properties,
|
||||||
functions,
|
functions,
|
||||||
signals,
|
signals,
|
||||||
variants,
|
variants,
|
||||||
|
}),
|
||||||
};
|
};
|
||||||
|
|
||||||
outtypes.insert(mapping.name.clone(), outform::TypeInfo::Class(type_));
|
outtypes.insert(mapping.name.clone(), type_);
|
||||||
}
|
}
|
||||||
|
|
||||||
for enum_ in typespec.enums {
|
for enum_ in typespec.enums {
|
||||||
if enum_.module.as_ref().map(|v| v as &str) == Some(module) {
|
if enum_.module.as_ref().map(|v| v as &str) == Some(module) {
|
||||||
outtypes.insert(
|
outtypes.insert(enum_.name.clone(), outform::TypeInfo {
|
||||||
enum_.name,
|
name: enum_.name,
|
||||||
outform::TypeInfo::Enum(outform::EnumInfo {
|
module: enum_.module.unwrap(),
|
||||||
|
details: outform::TypeDetails::Enum(outform::EnumInfo {
|
||||||
description: enum_.description,
|
description: enum_.description,
|
||||||
details: enum_.details,
|
details: enum_.details,
|
||||||
variants: enum_
|
variants: enum_
|
||||||
|
@ -278,7 +283,7 @@ pub fn resolve_types(
|
||||||
})
|
})
|
||||||
.collect(),
|
.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