From e0a0d3bdd17f7d0c6e068710e0ccfd6834e484f8 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 3 Dec 2025 01:16:37 +0000 Subject: [PATCH 1/3] Initial plan From 511e8db971bc0261d2908e6918ab3099962e390f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 3 Dec 2025 01:28:57 +0000 Subject: [PATCH 2/3] Add wiki pages support with @wiki, @header, @text, @br, @code tags Co-authored-by: ventz-lgtm <4554439+ventz-lgtm@users.noreply.github.com> --- builder/src/components/App/index.tsx | 3 + builder/src/pages/WikiPage/index.tsx | 92 +++++++++++++++++++ builder/src/util/parsed.ts | 19 +++- parser/examples/wikis/getting_started.lua | 21 +++++ parser/src/classes/Project/Category.ts | 22 +++-- parser/src/classes/Project/CategoryProject.ts | 12 +++ parser/src/classes/Project/WikiPage.ts | 85 +++++++++++++++++ 7 files changed, 247 insertions(+), 7 deletions(-) create mode 100644 builder/src/pages/WikiPage/index.tsx create mode 100644 parser/examples/wikis/getting_started.lua create mode 100644 parser/src/classes/Project/WikiPage.ts diff --git a/builder/src/components/App/index.tsx b/builder/src/components/App/index.tsx index 9df2678..7f853ca 100644 --- a/builder/src/components/App/index.tsx +++ b/builder/src/components/App/index.tsx @@ -9,6 +9,7 @@ import { project, title } from "../../util/parsed"; import FunctionPage from "../../pages/FunctionPage"; import TablePage from "../../pages/TablePage"; import CategoryPage from "../../pages/CategoryPage"; +import WikiPage from "../../pages/WikiPage"; import { dark } from "../../styles/themes/dark"; import { Helmet } from "react-helmet"; @@ -29,6 +30,8 @@ const RouteController: React.FC<{}> = () => { if (item.item.startsWith("category")) { return ; + } else if (item.item === "wiki") { + return ; } else if (item.item.endsWith("table")) { return ; } diff --git a/builder/src/pages/WikiPage/index.tsx b/builder/src/pages/WikiPage/index.tsx new file mode 100644 index 0000000..1e3cb8a --- /dev/null +++ b/builder/src/pages/WikiPage/index.tsx @@ -0,0 +1,92 @@ +import React from "react"; +import Page from "../Page"; +import { useParams } from "react-router-dom"; +import { project, WikiPage as WikiPageObject, WikiContent } from "../../util/parsed"; +import marked from "../../util/marked"; +import { SectionContainer, Section } from "../Page/styles"; +import Prism from "prismjs"; +import "prismjs/components/prism-lua"; + +const WikiPage: React.FC<{}> = () => { + const { tab, category } = useParams(); + const category_object = project[tab]?.subcategories?.[category]; + const item = category_object as WikiPageObject; + const description = item.description; + const content: WikiContent[] = item.content ?? []; + + function markedDescription() { + return { + __html: marked(description as string), + }; + } + + function renderContent() { + const elements: JSX.Element[] = []; + let currentParagraph: string[] = []; + + const flushParagraph = () => { + if (currentParagraph.length > 0) { + const text = currentParagraph.join(" "); + elements.push( +

+ ); + currentParagraph = []; + } + }; + + content.forEach((item, index) => { + switch (item.type) { + case "header": + flushParagraph(); + elements.push( +

{item.content}
+ ); + break; + case "text": + currentParagraph.push(item.content); + break; + case "br": + flushParagraph(); + break; + case "code": + flushParagraph(); + const highlighted = Prism.highlight( + item.content, + Prism.languages.lua, + "lua" + ); + elements.push( +
+							
+						
+ ); + break; + } + }); + + flushParagraph(); + return elements; + } + + return ( + + {description && ( + <> +
Description
+ + + )} + {renderContent()} +
+ ); +}; + +export default WikiPage; diff --git a/builder/src/util/parsed.ts b/builder/src/util/parsed.ts index b3a7fe4..7f7ea4c 100644 --- a/builder/src/util/parsed.ts +++ b/builder/src/util/parsed.ts @@ -7,6 +7,7 @@ import { mdiFormatListNumbered, mdiHook, mdiViewQuilt, + mdiFileDocument, } from "@mdi/js"; import * as mdiIcons from "@mdi/js"; @@ -51,6 +52,21 @@ export interface TablePage { item: "table"; } +export interface WikiContent { + type: "header" | "text" | "code" | "br"; + content: string; +} + +export interface WikiPage { + name: string; + description?: string; + content: WikiContent[]; + realm?: string; + internal?: boolean; + deprecated?: boolean; + item: "wiki"; +} + export interface Category { name: string; description?: string; @@ -64,7 +80,7 @@ export interface Category { item: "category"; } -export type ValidSubcategory = Category | FunctionPage | TablePage; +export type ValidSubcategory = Category | FunctionPage | TablePage | WikiPage; export interface ProjectStructure { [key: string]: Category; @@ -90,6 +106,7 @@ export const icons: { panels: mdiViewQuilt, enums: mdiFormatListNumbered, structs: mdiDatabase, + wikis: mdiFileDocument, default: mdiCursorDefault, }; diff --git a/parser/examples/wikis/getting_started.lua b/parser/examples/wikis/getting_started.lua new file mode 100644 index 0000000..ba465eb --- /dev/null +++ b/parser/examples/wikis/getting_started.lua @@ -0,0 +1,21 @@ +-- @wiki Getting Started +-- This wiki page explains how to get started with the project. +-- +-- @header Introduction +-- @text Welcome to the documentation. This guide will help you understand +-- @text how to use the wiki pages feature in gdocs. +-- @br +-- @text Wiki pages allow you to create rich documentation with headers, +-- @text text paragraphs, and code examples. +-- +-- @header Example Code +-- @text Here is an example of how to use the library: +-- @code +-- local function example() +-- print("Hello, World!") +-- end +-- +-- @header Another Section +-- @text This is another section with more text. +-- @br +-- @text After a break, we start a new paragraph. diff --git a/parser/src/classes/Project/Category.ts b/parser/src/classes/Project/Category.ts index ae78d1e..31a7f0f 100644 --- a/parser/src/classes/Project/Category.ts +++ b/parser/src/classes/Project/Category.ts @@ -4,10 +4,11 @@ import { DocBlock } from "../Parser/Tags.ts"; import { get_multiple, get_unique } from "../../utils/functions.ts"; import AliasTag from "../Tags/AliasTag.ts"; import TablePage, { FieldInfo } from "./TablePage.ts"; +import WikiPage from "./WikiPage.ts"; -export type ValidSubcategory = Category | FunctionPage | TablePage; +export type ValidSubcategory = Category | FunctionPage | TablePage | WikiPage; -export type ValidPageTypes = "function" | "table"; +export type ValidPageTypes = "function" | "table" | "wiki"; export default class Category { readonly subcategories: { @@ -72,17 +73,26 @@ export default class Category { .map((tag) => tag[0]) .join("\n\n") .trim(); - const page = this.pageType === "function" - ? new FunctionPage( + let page: FunctionPage | TablePage | WikiPage; + if (this.pageType === "wiki") { + page = new WikiPage( name, description != "" ? description : undefined, block, - ) - : new TablePage( + ); + } else if (this.pageType === "table") { + page = new TablePage( name, description != "" ? description : undefined, block, ); + } else { + page = new FunctionPage( + name, + description != "" ? description : undefined, + block, + ); + } if (has_subcategory) { const subcategory = get_unique(block, "subcategory") as string; diff --git a/parser/src/classes/Project/CategoryProject.ts b/parser/src/classes/Project/CategoryProject.ts index 07a2d09..a0fcb2a 100644 --- a/parser/src/classes/Project/CategoryProject.ts +++ b/parser/src/classes/Project/CategoryProject.ts @@ -39,6 +39,11 @@ export default class CategoryProject { this.add_tag(new BooleanTag("internal")); this.add_tag(new BooleanTag("deprecated")); this.add_tag(new BooleanTag("stub")); + /* Wiki-specific tags */ + this.add_tag(new Tag("header", 1, false)); + this.add_tag(new Tag("text", 1, false, false, true)); + this.add_tag(new Tag("code", 1, false, false, true)); + this.add_tag(new Tag("br", 0, false)); this.add_tag( new AliasTag("hook", 2, ([subcategory, name]) => [ "@category hooks", @@ -84,6 +89,13 @@ export default class CategoryProject { false, true, ); + this.add_category( + new Category("Wikis", "wiki"), + false, + "wiki", + false, + true, + ); /* Default categories that define types. */ this.add_category_type("Classes"); diff --git a/parser/src/classes/Project/WikiPage.ts b/parser/src/classes/Project/WikiPage.ts new file mode 100644 index 0000000..5e6cb66 --- /dev/null +++ b/parser/src/classes/Project/WikiPage.ts @@ -0,0 +1,85 @@ +import { DocBlock, TagInfo } from "../Parser/Tags.ts"; +import { get_unique } from "../../utils/functions.ts"; + +export interface WikiContent { + type: "header" | "text" | "code" | "br"; + content: string; +} + +export default class WikiPage { + readonly item: "wiki"; + readonly content: WikiContent[]; + readonly realm?: string; + readonly internal?: boolean; + readonly deprecated?: boolean; + + constructor( + public readonly name: string, + public readonly description?: string, + block: DocBlock = {}, + ) { + // Collect all content items with their line numbers for ordering + const contentItems: { line: number; type: WikiContent["type"]; content: string }[] = []; + + // Process headers + if (block["header"]) { + block["header"].forEach((tag: TagInfo) => { + contentItems.push({ + line: tag.line, + type: "header", + content: tag.args?.[0] ?? "", + }); + }); + } + + // Process text blocks + if (block["text"]) { + block["text"].forEach((tag: TagInfo) => { + contentItems.push({ + line: tag.line, + type: "text", + content: tag.args?.[0] ?? "", + }); + }); + } + + // Process code blocks + if (block["code"]) { + block["code"].forEach((tag: TagInfo) => { + contentItems.push({ + line: tag.line, + type: "code", + content: tag.args?.[0] ?? "", + }); + }); + } + + // Process br (break) tags + if (block["br"]) { + block["br"].forEach((tag: TagInfo) => { + contentItems.push({ + line: tag.line, + type: "br", + content: "", + }); + }); + } + + // Sort by line number to preserve original order + contentItems.sort((a, b) => a.line - b.line); + + // Convert to WikiContent format + this.content = contentItems.map(({ type, content }) => ({ type, content })); + this.realm = get_unique(block, "realm"); + this.internal = get_unique(block, "internal") === "true" ? true : undefined; + this.deprecated = get_unique(block, "deprecated") === "true" + ? true + : undefined; + + this.item = "wiki"; + } + + print(level = 0) { + console.log(" ".repeat(level) + this.name); + } +} From 8f506991a1ce671e1306227dfd09938a69d2d03f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 3 Dec 2025 01:33:39 +0000 Subject: [PATCH 3/3] Address code review feedback: extract code rendering, add error handling Co-authored-by: ventz-lgtm <4554439+ventz-lgtm@users.noreply.github.com> --- builder/src/pages/WikiPage/index.tsx | 32 +++++++++++++++++----------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/builder/src/pages/WikiPage/index.tsx b/builder/src/pages/WikiPage/index.tsx index 1e3cb8a..ea01388 100644 --- a/builder/src/pages/WikiPage/index.tsx +++ b/builder/src/pages/WikiPage/index.tsx @@ -7,6 +7,24 @@ import { SectionContainer, Section } from "../Page/styles"; import Prism from "prismjs"; import "prismjs/components/prism-lua"; +const CODE_LANGUAGE = "lua"; +const CODE_CLASS = `language-${CODE_LANGUAGE}`; + +const renderCodeBlock = (code: string, key: string) => { + const language = Prism.languages[CODE_LANGUAGE]; + const highlighted = language + ? Prism.highlight(code, language, CODE_LANGUAGE) + : code; + return ( +
+			
+		
+ ); +}; + const WikiPage: React.FC<{}> = () => { const { tab, category } = useParams(); const category_object = project[tab]?.subcategories?.[category]; @@ -53,19 +71,7 @@ const WikiPage: React.FC<{}> = () => { break; case "code": flushParagraph(); - const highlighted = Prism.highlight( - item.content, - Prism.languages.lua, - "lua" - ); - elements.push( -
-							
-						
- ); + elements.push(renderCodeBlock(item.content, `code-${index}`)); break; } });