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

View File

@ -23,6 +23,7 @@ use crate::pasta::{AliasList, Docs, ValuePath};
/// Match Non-Primop
/// Eq position
pub fn find_aliases(item: &Docs, list: &Vec<&Docs>) -> AliasList {
dbg!("find alias for", &item.path);
let res: AliasList = list
.iter()
.filter_map(|other| {
@ -54,6 +55,7 @@ pub fn find_aliases(item: &Docs, list: &Vec<&Docs>) -> AliasList {
None
}
(false, false) => {
dbg!("this case", s_meta.countApplied);
if s_meta.countApplied != Some(0) {
if item.path.last() == other.path.last() {
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
&& s_meta.countApplied == Some(0)
&& s_meta.countApplied == o_meta.countApplied
&& (s_meta.countApplied == Some(0) || o_meta.countApplied == Some(0))
{
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 />
</FilterProvider>
</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={{
display: {
xs: "none",
lg: "block",
md: "block",
},
position: "fixed",
top: "6rem",
right: "1.8em",
position: "sticky",
top: "3.7rem",
p: 1,
order: 3,
whiteSpace: "nowrap",
}}
>
<Typography variant="subtitle1">Table of Contents</Typography>
<Typography variant="subtitle1">On this page</Typography>
<Box sx={{ display: "flex", flexDirection: "column" }}>
{headings.map((h, idx) => (
<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 meta = item?.meta;
const signature = meta?.signature || (item && findType(item)) || "";
const { args: argTypes, returns: retTypes } = interpretType(
meta?.path[meta?.path?.length - 1],
meta?.signature || (item && findType(item)) || ""
signature
);
const position =
@ -107,6 +109,11 @@ export default async function Page(props: { params: { path: string[] } }) {
meta?.is_primop && meta?.primop_meta
? getPrimopDescription(meta.primop_meta) + mdxSource
: mdxSource;
// Skip generating this builtin.
// It is internal information of noogle.
if (meta?.title === "builtins.lambdaMeta") {
return undefined;
}
return (
<>
@ -118,11 +125,18 @@ export default async function Page(props: { params: { path: string[] } }) {
maxWidth: "100vw",
minHeight: "calc(100vh - 3.7rem)",
overflow: "hidden",
gridColumnStart: 2,
p: { xs: 1, md: 2 },
bgcolor: "background.paper",
}}
>
<HighlightBaseline />
{meta?.path &&
meta.path.map((attr, idx) => (
<Box sx={{ display: "none" }} key={`${idx}`}>
{attr}
</Box>
))}
<Box>
<Box
sx={{
@ -180,6 +194,7 @@ export default async function Page(props: { params: { path: string[] } }) {
>
No documentation found yet.
</Typography>
{!position && (
<div data-pagefind-ignore="all">
<Typography variant="h5" sx={{ pt: 2 }}>
@ -227,6 +242,28 @@ export default async function Page(props: { params: { path: string[] } }) {
</Typography>
</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>
)}
<MDXRemote
@ -299,33 +336,59 @@ export default async function Page(props: { params: { path: string[] } }) {
</Typography>
</div>
)}
{!!meta?.aliases?.length && (
<div data-pagefind-ignore="all">
<Divider flexItem />
<Typography
variant="subtitle1"
component={"h3"}
sx={{
color: "text.secondary",
alignSelf: "center",
pb: 2,
}}
>
Noogle also knows
</Typography>
<Typography variant="h5" component={"h3"}>
Aliases
</Typography>
<ul>
{meta?.aliases?.map((a) => (
<li key={a.join(".")}>
<Link href={`/f/${a.join("/")}`}>{a.join(".")}</Link>
</li>
))}
</ul>
</div>
)}
<div data-pagefind-ignore="all">
{(!!meta?.aliases?.length || !!signature) && (
<>
<Divider flexItem />
<Typography
variant="subtitle1"
component={"h3"}
sx={{
color: "text.secondary",
alignSelf: "center",
pb: 2,
}}
>
Noogle also knows
</Typography>
</>
)}
{!!meta?.aliases?.length && (
<>
<Typography
variant="h5"
component={"div"}
sx={{ color: "text.secondary" }}
>
Aliases
</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>
<Divider flexItem sx={{ mt: 2 }} />
</Box>

View File

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

View File

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

View File

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

View File

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

View File

@ -7,7 +7,6 @@ import {
Typography,
} from "@mui/material";
import GitHubIcon from "@mui/icons-material/GitHub";
import PublicIcon from "@mui/icons-material/Public";
import { Background } from "./Background";
export interface LayoutProps {
@ -20,25 +19,14 @@ export const SocialIcons = () => {
<Link
href="https://github.com/nix-community/noogle"
target="_blank"
sx={{ color: "text.primary" }}
sx={{ color: "inherit" }}
>
<Tooltip title="Github">
<IconButton color="inherit">
<IconButton color="inherit" aria-label="nixos github">
<GitHubIcon />
</IconButton>
</Tooltip>
</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";
import { useTheme } from "@mui/material";
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 ReactMarkdown from "react-markdown";
import rehypeHighlight from "rehype-highlight";
@ -32,7 +34,15 @@ export const MarkdownPreview = (props: MarkdownPreviewProps) => {
h3: "h5",
h4: "h6",
}}
rehypePlugins={[[rehypeHighlight, { languages: { nix } }]]}
rehypePlugins={[
[
rehypeHighlight,
{
detect: true,
languages: { nix, haskell, bash, default: nix },
},
],
]}
>
{description}
</ReactMarkdown>

View File

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