fix layout, add more tests

This commit is contained in:
Johannes Kirschbauer 2023-12-30 22:15:48 +01:00 committed by Johannes Kirschbauer
parent 922f09e340
commit 52758ae423
15 changed files with 238 additions and 142 deletions

View File

@ -287,7 +287,7 @@ fn indent_list_item_content(body: &str, indent: &str) -> String {
if line_nr > 0 { if line_nr > 0 {
res.push_str(&format!("{} {}\n", indent, line.trim())); res.push_str(&format!("{} {}\n", indent, line.trim()));
} else { } else {
res.push_str(&format!("{}",line.trim())) res.push_str(&format!("{}", line.trim()))
} }
} }
res res
@ -314,8 +314,10 @@ fn format_comment(text: &str, token: &SyntaxToken) -> String {
let mut markdown = parse_doc_comment(&lines.join("\n"), indentation + 2); let mut markdown = parse_doc_comment(&lines.join("\n"), indentation + 2);
if let Some(argument_docs) = get_argument_docs(token, &indent_2) { if let Some(argument_docs) = get_argument_docs(token, &indent_2) {
markdown.push_str(&format!("\n\n{indent_2}# Arguments")); if !argument_docs.trim().is_empty() {
markdown.push_str(&format!("\n\n{argument_docs}")); markdown.push_str(&format!("\n\n{indent_2}# Arguments"));
markdown.push_str(&format!("\n\n{argument_docs}"));
}
} }
return format!("/**\n{}\n{}*/", markdown, indent_1); return format!("/**\n{}\n{}*/", markdown, indent_1);

View File

@ -23,6 +23,7 @@ use crate::pasta::{AliasList, Docs, ValuePath};
/// Match Non-Primop /// Match Non-Primop
/// Eq position /// Eq position
pub fn find_aliases(item: &Docs, list: &Vec<&Docs>) -> AliasList { pub fn find_aliases(item: &Docs, list: &Vec<&Docs>) -> AliasList {
dbg!("find alias for", &item.path);
let res: AliasList = list let res: AliasList = list
.iter() .iter()
.filter_map(|other| { .filter_map(|other| {
@ -54,6 +55,7 @@ pub fn find_aliases(item: &Docs, list: &Vec<&Docs>) -> AliasList {
None None
} }
(false, false) => { (false, false) => {
dbg!("this case", s_meta.countApplied);
if s_meta.countApplied != Some(0) { if s_meta.countApplied != Some(0) {
if item.path.last() == other.path.last() { if item.path.last() == other.path.last() {
return Some(other.path.clone()); return Some(other.path.clone());
@ -61,8 +63,7 @@ pub fn find_aliases(item: &Docs, list: &Vec<&Docs>) -> AliasList {
} }
if s_meta.position == o_meta.position if s_meta.position == o_meta.position
&& s_meta.countApplied == Some(0) && (s_meta.countApplied == Some(0) || o_meta.countApplied == Some(0))
&& s_meta.countApplied == o_meta.countApplied
{ {
return Some(other.path.clone()); return Some(other.path.clone());
} }

View File

@ -0,0 +1,30 @@
[
{
"aliases": [
[
"lib",
"lists",
"foldr"
]
],
"path": [
"lib",
"lists",
"fold"
]
},
{
"aliases": [
[
"lib",
"lists",
"fold"
]
],
"path": [
"lib",
"lists",
"foldr"
]
}
]

View File

@ -0,0 +1,42 @@
[
{
"docs": {
"attr": {
"position": {
"column": 3,
"file": "/nix/store/ba0p7n38ncj0gx55yj2vddx189nkljs0-nixpkgs-migrated/lib/lists.nix",
"line": 108
}
},
"lambda": {
"isPrimop": false,
"position": {
"column": 11,
"file": "/nix/store/ba0p7n38ncj0gx55yj2vddx189nkljs0-nixpkgs-migrated/lib/lists.nix",
"line": 95
}
}
},
"path": ["lib", "lists", "fold"]
},
{
"docs": {
"attr": {
"position": {
"column": 3,
"file": "/nix/store/ba0p7n38ncj0gx55yj2vddx189nkljs0-nixpkgs-migrated/lib/lists.nix",
"line": 95
}
},
"lambda": {
"isPrimop": false,
"position": {
"column": 11,
"file": "/nix/store/ba0p7n38ncj0gx55yj2vddx189nkljs0-nixpkgs-migrated/lib/lists.nix",
"line": 95
}
}
},
"path": ["lib", "lists", "foldr"]
}
]

View File

@ -11,7 +11,21 @@ export default function SearchLayout({ children }: { children: ReactNode }) {
<Header /> <Header />
</FilterProvider> </FilterProvider>
</Suspense> </Suspense>
<Container maxWidth="lg">{children}</Container> <Container
disableGutters
maxWidth="lg"
sx={{
display: {
xs: "block",
md: "grid",
},
// display: "grid",
gridTemplateColumns: "1fr 6fr 1fr",
alignItems: "start",
}}
>
{children}
</Container>
</> </>
); );
} }

View File

@ -47,15 +47,16 @@ const Toc = async (props: TocProps) => {
sx={{ sx={{
display: { display: {
xs: "none", xs: "none",
lg: "block", md: "block",
}, },
position: "fixed", position: "sticky",
top: "6rem", top: "3.7rem",
right: "1.8em", p: 1,
order: 3,
whiteSpace: "nowrap", whiteSpace: "nowrap",
}} }}
> >
<Typography variant="subtitle1">Table of Contents</Typography> <Typography variant="subtitle1">On this page</Typography>
<Box sx={{ display: "flex", flexDirection: "column" }}> <Box sx={{ display: "flex", flexDirection: "column" }}>
{headings.map((h, idx) => ( {headings.map((h, idx) => (
<Link key={idx} href={`#${h.id}`}> <Link key={idx} href={`#${h.id}`}>
@ -88,9 +89,10 @@ export default async function Page(props: { params: { path: string[] } }) {
const mdxSource = item?.content?.content || ""; const mdxSource = item?.content?.content || "";
const meta = item?.meta; const meta = item?.meta;
const signature = meta?.signature || (item && findType(item)) || "";
const { args: argTypes, returns: retTypes } = interpretType( const { args: argTypes, returns: retTypes } = interpretType(
meta?.path[meta?.path?.length - 1], meta?.path[meta?.path?.length - 1],
meta?.signature || (item && findType(item)) || "" signature
); );
const position = const position =
@ -107,6 +109,11 @@ export default async function Page(props: { params: { path: string[] } }) {
meta?.is_primop && meta?.primop_meta meta?.is_primop && meta?.primop_meta
? getPrimopDescription(meta.primop_meta) + mdxSource ? getPrimopDescription(meta.primop_meta) + mdxSource
: mdxSource; : mdxSource;
// Skip generating this builtin.
// It is internal information of noogle.
if (meta?.title === "builtins.lambdaMeta") {
return undefined;
}
return ( return (
<> <>
@ -118,11 +125,18 @@ export default async function Page(props: { params: { path: string[] } }) {
maxWidth: "100vw", maxWidth: "100vw",
minHeight: "calc(100vh - 3.7rem)", minHeight: "calc(100vh - 3.7rem)",
overflow: "hidden", overflow: "hidden",
gridColumnStart: 2,
p: { xs: 1, md: 2 }, p: { xs: 1, md: 2 },
bgcolor: "background.paper", bgcolor: "background.paper",
}} }}
> >
<HighlightBaseline /> <HighlightBaseline />
{meta?.path &&
meta.path.map((attr, idx) => (
<Box sx={{ display: "none" }} key={`${idx}`}>
{attr}
</Box>
))}
<Box> <Box>
<Box <Box
sx={{ sx={{
@ -180,6 +194,7 @@ export default async function Page(props: { params: { path: string[] } }) {
> >
No documentation found yet. No documentation found yet.
</Typography> </Typography>
{!position && ( {!position && (
<div data-pagefind-ignore="all"> <div data-pagefind-ignore="all">
<Typography variant="h5" sx={{ pt: 2 }}> <Typography variant="h5" sx={{ pt: 2 }}>
@ -227,6 +242,28 @@ export default async function Page(props: { params: { path: string[] } }) {
</Typography> </Typography>
</div> </div>
)} )}
{position && (
<Link
target="_blank"
href={getSourcePosition(
"https://github.com/hsjobeki/nixpkgs/tree/migrate-doc-comments",
position
)}
>
<Button
data-pagefind-ignore="all"
variant="text"
sx={{
textTransform: "none",
my: 1,
placeSelf: "start",
}}
startIcon={<LinkIcon />}
>
Original/underlying function
</Button>
</Link>
)}
</Box> </Box>
)} )}
<MDXRemote <MDXRemote
@ -299,33 +336,59 @@ export default async function Page(props: { params: { path: string[] } }) {
</Typography> </Typography>
</div> </div>
)} )}
{!!meta?.aliases?.length && ( <div data-pagefind-ignore="all">
<div data-pagefind-ignore="all"> {(!!meta?.aliases?.length || !!signature) && (
<Divider flexItem /> <>
<Typography <Divider flexItem />
variant="subtitle1" <Typography
component={"h3"} variant="subtitle1"
sx={{ component={"h3"}
color: "text.secondary", sx={{
alignSelf: "center", color: "text.secondary",
pb: 2, alignSelf: "center",
}} pb: 2,
> }}
Noogle also knows >
</Typography> Noogle also knows
</Typography>
<Typography variant="h5" component={"h3"}> </>
Aliases )}
</Typography> {!!meta?.aliases?.length && (
<ul> <>
{meta?.aliases?.map((a) => ( <Typography
<li key={a.join(".")}> variant="h5"
<Link href={`/f/${a.join("/")}`}>{a.join(".")}</Link> component={"div"}
</li> sx={{ color: "text.secondary" }}
))} >
</ul> Aliases
</div> </Typography>
)} <ul>
{meta?.aliases?.map((a) => (
<li key={a.join(".")}>
<Link href={`/f/${a.join("/")}`}>{a.join(".")}</Link>
</li>
))}
</ul>
</>
)}
{!!signature && !meta?.signature && (
<>
<Typography
variant="h5"
component={"div"}
sx={{ color: "text.secondary" }}
>
Detected Type
</Typography>
<MDXRemote
options={{
mdxOptions: mdxRenderOptions,
}}
source={`\`\`\`haskell\n${signature.trim()}\n\`\`\`\n`}
/>
</>
)}
</div>
</Box> </Box>
<Divider flexItem sx={{ mt: 2 }} /> <Divider flexItem sx={{ mt: 2 }} />
</Box> </Box>

View File

@ -21,7 +21,7 @@ export const BackButton = () => {
} }
}; };
return ( return (
<IconButton onClick={() => handleBack()}> <IconButton onClick={() => handleBack()} aria-label="Back">
<ChevronLeft /> <ChevronLeft />
</IconButton> </IconButton>
); );

View File

@ -1,57 +0,0 @@
import { Doc } from "@/models/data";
import bash from "highlight.js/lib/languages/bash";
import haskell from "highlight.js/lib/languages/haskell";
import nix from "highlight.js/lib/languages/nix";
import rehypeHighlight from "rehype-highlight";
import { rehypeExtractExcerpt } from "@/excerpt";
import Markdown from "react-markdown";
import { HighlightBaseline } from "./HighlightBaseline";
import rehypeStringify from "rehype-stringify";
import remarkParse from "remark-parse";
import remarkRehype from "remark-rehype";
import { unified } from "unified";
import { useEffect, useState } from "react";
const getExcerpt = async (content: string): Promise<string> => {
const processor = unified()
.use(remarkParse)
.use(remarkRehype)
.use(rehypeExtractExcerpt)
.use(rehypeStringify);
const result = await processor.process(content);
return result.data["excerpt"] as string;
};
export const Excerpt = ({ meta, content }: Doc) => {
const mdxSource = content?.content || "";
const [excerpt, setExcerpt] = useState<string>("");
useEffect(() => {
getExcerpt(mdxSource).then((r) => setExcerpt(r));
}, [mdxSource]);
return (
<>
<HighlightBaseline />
<Markdown
components={{
h1: "h2",
h2: "h3",
h3: "h4",
h4: "h5",
}}
rehypePlugins={[
[
rehypeHighlight,
{
detect: true,
languages: { nix, haskell, bash, default: nix },
},
],
]}
>
{excerpt}
</Markdown>
</>
);
};

View File

@ -3,7 +3,6 @@ import {
Box, Box,
Chip, Chip,
Container, Container,
Divider,
IconButton, IconButton,
LinearProgress, LinearProgress,
Link, Link,
@ -17,17 +16,15 @@ import {
} from "@mui/material"; } from "@mui/material";
import React, { useEffect, useMemo, useState } from "react"; import React, { useEffect, useMemo, useState } from "react";
// import { useMiniSearch } from "react-minisearch";
// import { Doc, data } from "@/models/data";
import { EmptyRecordsPlaceholder } from "./emptyRecordsPlaceholder"; import { EmptyRecordsPlaceholder } from "./emptyRecordsPlaceholder";
import { useSearchParams } from "next/navigation"; import { useSearchParams } from "next/navigation";
// import { Excerpt } from "./Excerpt";
import { useRouter } from "next/navigation"; import { useRouter } from "next/navigation";
import { PagefindResult, RawResult, usePagefindSearch } from "./Pagefind"; import { PagefindResult, RawResult, usePagefindSearch } from "./Pagefind";
import { Clear } from "@mui/icons-material"; import { Clear } from "@mui/icons-material";
import { useFilter } from "./layout/filterContext"; import { useFilter } from "./layout/filterContext";
// import d from "./example.json";
export type BasicListItem = { export type BasicListItem = {
item: React.ReactNode; item: React.ReactNode;
key: string; key: string;
@ -35,9 +32,6 @@ export type BasicListItem = {
const useMobile = () => useMediaQuery(useTheme().breakpoints.down("md")); const useMobile = () => useMediaQuery(useTheme().breakpoints.down("md"));
// interface SearchResultsProps {
// pageItems: PagefindResult[];
// }
export function PagefindResults() { export function PagefindResults() {
const params = useSearchParams(); const params = useSearchParams();
const router = useRouter(); const router = useRouter();
@ -87,6 +81,7 @@ export function PagefindResults() {
const loadData = async () => { const loadData = async () => {
let items = await Promise.all(pageItems.map(async (r) => await r.data())); let items = await Promise.all(pageItems.map(async (r) => await r.data()));
setItems(items); setItems(items);
// setItems(d);
}; };
loadData(); loadData();
}, [pageItems]); }, [pageItems]);
@ -132,7 +127,6 @@ export function PagefindResults() {
component="span" component="span"
variant="subtitle1" variant="subtitle1"
sx={{ sx={{
color: "text.secondary",
p: 1, p: 1,
textTransform: "capitalize", textTransform: "capitalize",
}} }}
@ -148,7 +142,6 @@ export function PagefindResults() {
component="span" component="span"
variant="subtitle1" variant="subtitle1"
sx={{ sx={{
color: "text.secondary",
p: 1, p: 1,
textTransform: "capitalize", textTransform: "capitalize",
}} }}
@ -160,6 +153,7 @@ export function PagefindResults() {
<IconButton <IconButton
size="small" size="small"
onClick={() => handleReset("filter")} onClick={() => handleReset("filter")}
aria-label="clear filter"
> >
<Clear fontSize="inherit" /> <Clear fontSize="inherit" />
</IconButton> </IconButton>
@ -175,9 +169,8 @@ export function PagefindResults() {
component="span" component="span"
variant="subtitle1" variant="subtitle1"
sx={{ sx={{
color: "text.secondary",
p: 1, p: 1,
textTransform: "capitalize", textTransform: "none",
}} }}
> >
<Chip <Chip
@ -187,6 +180,7 @@ export function PagefindResults() {
<IconButton <IconButton
size="small" size="small"
onClick={() => handleReset("term")} onClick={() => handleReset("term")}
aria-label="clear term"
> >
<Clear fontSize="inherit" /> <Clear fontSize="inherit" />
</IconButton> </IconButton>
@ -197,11 +191,11 @@ export function PagefindResults() {
/> />
</Typography> </Typography>
)} )}
<List aria-label="basic-list" sx={{ pt: 0, width: "100%" }}> <List aria-label="basic-list" sx={{ pt: 1, width: "100%" }}>
{items.length ? ( {items.length ? (
items.map(({ meta, excerpt, url }, idx) => ( items.map(({ meta, excerpt, url }, idx) => (
<Box key={`${idx}`}> <React.Fragment key={`${idx}`}>
<ListItem sx={{ px: 0 }} aria-label={`item-${idx}`}> <ListItem sx={{ px: 0, py: 1 }} aria-label={`item-${idx}`}>
<ListItemText <ListItemText
primaryTypographyProps={{ primaryTypographyProps={{
variant: "h5", variant: "h5",
@ -216,15 +210,10 @@ export function PagefindResults() {
} }
/> />
</ListItem> </ListItem>
<Divider </React.Fragment>
flexItem
orientation="horizontal"
sx={{ p: 1, mx: 1 }}
/>
</Box>
)) ))
) : ( ) : (
<Box sx={{ mt: 3 }}> <Box component="li" sx={{ mt: 3 }}>
<EmptyRecordsPlaceholder <EmptyRecordsPlaceholder
CardProps={{ CardProps={{
sx: { backgroundColor: "inherit" }, sx: { backgroundColor: "inherit" },

View File

@ -20,7 +20,6 @@ import { useMiniSearch } from "react-minisearch";
import { Doc, data } from "@/models/data"; import { Doc, data } from "@/models/data";
import { EmptyRecordsPlaceholder } from "./emptyRecordsPlaceholder"; import { EmptyRecordsPlaceholder } from "./emptyRecordsPlaceholder";
import { useSearchParams } from "next/navigation"; import { useSearchParams } from "next/navigation";
import { Excerpt } from "./Excerpt";
import { useRouter } from "next/navigation"; import { useRouter } from "next/navigation";
export type BasicListItem = { export type BasicListItem = {
@ -121,7 +120,7 @@ export function SearchResults() {
{meta.title} {meta.title}
</Link> </Link>
} }
secondary={<Excerpt meta={meta} content={content} />} secondary={""}
/> />
</ListItem> </ListItem>
<Divider <Divider

View File

@ -92,7 +92,12 @@ export const Filter = (props: FilterProps) => {
return ( return (
<Collapse in={showFilter}> <Collapse in={showFilter}>
{showDivider && <Divider sx={{ mt: 1, mb: 2 }} />} {showDivider && <Divider sx={{ mt: 1, mb: 2 }} />}
<Container disableGutters> <Container
disableGutters
sx={{
py: 1,
}}
>
<Box <Box
sx={{ sx={{
display: "flex", display: "flex",

View File

@ -17,7 +17,7 @@ export const Header = () => {
top: 0, top: 0,
width: "100%", width: "100%",
py: 1.2, py: 1.2,
zIndex: 1, zIndex: 1000,
backgroundColor: backgroundColor:
theme.palette.mode === "light" ? "primary.main" : "#101010", theme.palette.mode === "light" ? "primary.main" : "#101010",
display: "grid", display: "grid",
@ -39,8 +39,9 @@ export const Header = () => {
sx={{ sx={{
color: "primary.contrastText", color: "primary.contrastText",
}} }}
aria-label="Home"
> >
<IconButton color="inherit"> <IconButton color="inherit" aria-label="Home">
<Home /> <Home />
</IconButton> </IconButton>
</Link> </Link>
@ -51,7 +52,7 @@ export const Header = () => {
display: { xs: "block", md: "none" }, display: { xs: "block", md: "none" },
}} }}
> >
<IconButton color="inherit"> <IconButton color="inherit" aria-label="Menu">
<Menu /> <Menu />
</IconButton> </IconButton>
</Box> </Box>
@ -79,6 +80,7 @@ export const Header = () => {
xs: "none", xs: "none",
md: "block", md: "block",
}, },
color: "primary.contrastText",
}} }}
> >
<SocialIcons /> <SocialIcons />
@ -88,7 +90,15 @@ export const Header = () => {
<Box sx={{ width: "100%", height: "3.7rem" }} /> <Box sx={{ width: "100%", height: "3.7rem" }} />
<Suspense fallback={<LinearProgress />}> <Suspense fallback={<LinearProgress />}>
<Box sx={{ bgcolor: "background.paper", px: 2 }}> <Box
sx={{
bgcolor: "background.paper",
px: 2,
position: "sticky",
top: "3.7rem",
zIndex: 10,
}}
>
<Filter disableChevron /> <Filter disableChevron />
</Box> </Box>
</Suspense> </Suspense>

View File

@ -7,7 +7,6 @@ import {
Typography, Typography,
} from "@mui/material"; } from "@mui/material";
import GitHubIcon from "@mui/icons-material/GitHub"; import GitHubIcon from "@mui/icons-material/GitHub";
import PublicIcon from "@mui/icons-material/Public";
import { Background } from "./Background"; import { Background } from "./Background";
export interface LayoutProps { export interface LayoutProps {
@ -20,25 +19,14 @@ export const SocialIcons = () => {
<Link <Link
href="https://github.com/nix-community/noogle" href="https://github.com/nix-community/noogle"
target="_blank" target="_blank"
sx={{ color: "text.primary" }} sx={{ color: "inherit" }}
> >
<Tooltip title="Github"> <Tooltip title="Github">
<IconButton color="inherit"> <IconButton color="inherit" aria-label="nixos github">
<GitHubIcon /> <GitHubIcon />
</IconButton> </IconButton>
</Tooltip> </Tooltip>
</Link> </Link>
<Link
href="https://nixos.org"
target="_blank"
sx={{ color: "text.primary" }}
>
<Tooltip title="NixOS">
<IconButton color="inherit">
<PublicIcon />
</IconButton>
</Tooltip>
</Link>
</> </>
); );
}; };

View File

@ -1,6 +1,8 @@
"use client"; "use client";
import { useTheme } from "@mui/material"; import { useTheme } from "@mui/material";
import nix from "highlight.js/lib/languages/nix"; import nix from "highlight.js/lib/languages/nix";
import haskell from "highlight.js/lib/languages/haskell";
import bash from "highlight.js/lib/languages/bash";
import { useEffect } from "react"; import { useEffect } from "react";
import ReactMarkdown from "react-markdown"; import ReactMarkdown from "react-markdown";
import rehypeHighlight from "rehype-highlight"; import rehypeHighlight from "rehype-highlight";
@ -32,7 +34,15 @@ export const MarkdownPreview = (props: MarkdownPreviewProps) => {
h3: "h5", h3: "h5",
h4: "h6", h4: "h6",
}} }}
rehypePlugins={[[rehypeHighlight, { languages: { nix } }]]} rehypePlugins={[
[
rehypeHighlight,
{
detect: true,
languages: { nix, haskell, bash, default: nix },
},
],
]}
> >
{description} {description}
</ReactMarkdown> </ReactMarkdown>

View File

@ -4,5 +4,5 @@ export const getPrimopDescription = (meta: PrimopMatter) => {
const args = meta?.args?.map((a) => `__${a}__`) || []; const args = meta?.args?.map((a) => `__${a}__`) || [];
return !meta?.arity return !meta?.arity
? "" ? ""
: `Takes __${meta?.arity}__ arguments\n\n ${args.join(", ")} \n`; : `Takes __${meta?.arity}__ arguments\n\n ${args.join(", ")} \n\n`;
}; };