diff --git a/.gitattributes b/.gitattributes index a158289..3784589 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,2 +1,2 @@ # https://github.com/github-linguist/linguist/blob/master/docs/overrides.md#documentation -examples/* -linguist-documentation +examples/* -linguist-documentation \ No newline at end of file diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml index dd60527..9564421 100644 --- a/.github/workflows/pages.yml +++ b/.github/workflows/pages.yml @@ -1,47 +1,46 @@ -name: Pages +name: Github Pages on: - workflow_dispatch: push: - branches: - - main + branches: ["zine", "main"] + pull_request: + workflow_dispatch: +# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages permissions: contents: read pages: write id-token: write +defaults: + run: + shell: bash + +# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued. concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true - jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 with: - fetch-depth: 0 - - name: Setup mdBook - uses: peaceiris/actions-mdbook@v1 + fetch-depth: 0 # Change if you need git info + - name: Setup Zine + uses: kristoff-it/setup-zine@v1 with: - mdbook-version: "latest" - - name: Cache Cargo - uses: actions/cache@v3 - with: - path: | - ~/.cargo/bin - key: pages-${{ runner.os }} - - run: | - if ! command -v mdbook-last-changed; then - cargo install mdbook-last-changed - fi - mdbook build + version: v0.10.2 + + - name: Build + run: zine release + - name: Upload artifact uses: actions/upload-pages-artifact@v3 with: - path: ./book + path: "public" + deploy: environment: @@ -49,7 +48,10 @@ jobs: url: ${{ steps.deployment.outputs.page_url }} runs-on: ubuntu-latest needs: build + if: github.event_name != 'pull_request' steps: + - name: Setup Pages + uses: actions/configure-pages@v5 - name: Deploy to GitHub Pages id: deployment - uses: actions/deploy-pages@v4 + uses: actions/deploy-pages@v4 \ No newline at end of file diff --git a/.gitignore b/.gitignore index 2004b31..4e69a86 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ -book +public/ zig-out/ zig-cache/ .zig-cache/ .DS_Store .tool-versions +.vscode \ No newline at end of file diff --git a/Makefile b/Makefile index 141cce7..8cbdf46 100644 --- a/Makefile +++ b/Makefile @@ -6,11 +6,11 @@ endif .PHONY: serve serve: - mdbook serve + zine .PHONY: lint lint: - npx prettier@2.7.1 --write book-src + npx prettier@2.7.1 --write src .PHONY: run run: @@ -35,5 +35,5 @@ EXCLUDE = --exclude "*webp" --exclude "*svg" --exclude "*gif" .PHONY: webp webp: - fd -t f $(EXCLUDE) --full-path './book-src/images' --exec convert {} {.}.webp \; - fd -t f $(EXCLUDE) --full-path './book-src/images' --exec rm {} \; + fd -t f $(EXCLUDE) --full-path './assets/images' --exec convert {} {.}.webp \; + fd -t f $(EXCLUDE) --full-path './assets/images' --exec rm {} \; diff --git a/static/giscus.js b/assets/giscus.js similarity index 99% rename from static/giscus.js rename to assets/giscus.js index 25ad42c..f46b446 100644 --- a/static/giscus.js +++ b/assets/giscus.js @@ -32,4 +32,4 @@ function appendGiscusScript() { pageDiv.appendChild(script); } -document.addEventListener('DOMContentLoaded', appendGiscusScript); +document.addEventListener('DOMContentLoaded', appendGiscusScript); \ No newline at end of file diff --git a/assets/highlight.css b/assets/highlight.css new file mode 100644 index 0000000..7206a6c --- /dev/null +++ b/assets/highlight.css @@ -0,0 +1,103 @@ +:root { + --code-fg: #BD976A; + --keyword: #4D9375; + --variable: #BD976A; + --comment: #758575DD; + --operator: #666666; + --string: #C98A7D; + --number: #4C9A91; + --function: #CB7676; + --bracket: #93aa9e; +} + +code { + color: var(--code-fg); +} + +code.zig, code.javascript, code.c, code.cpp, code.zon, code.go{ + color: var(--code-fg); + .keyword, .keyword_modifier, .type_builtin, .keyword_type, .keyword_return, .keyword_conditional, .keyword_repeat, .keyword_operator, .constant_builtin, .keyword_exception, .type{ + color: var(--keyword); + } + .variable, .function_builtin{ + color: var(--variable); + } + .comment{ + color: var(--comment); + } + .operator, .punctuation{ + color: var(--operator); + } + .string, .character{ + color: var(--string); + } + .number{ + color: var(--number); + } + .keyword_function, .punctuation_delimiter, .function{ + color: var(--function); + } + .punctuation_bracket{ + color: var(--bracket); + } +} + +code.conf{ + color: var(--code-fg); + .function{ + color: var(--function); + } + .punctuation_bracket{ + color: var(--bracket); + } +} + +code.diff{ + color: var(--code-fg); + .addition, .string{ + color: #4D9375; + } + .deletion, .keyword{ + color: #CB7676; + } +} + +/* TODO 分词器太烂了 */ +code.bash { + color: var(--code-fg); + .comment { + color: var(--comment); + font-style: italic; + } + span.operator { + color: var(--operator); + } + .constant { + color: var(--number); + } + .string { + color: var(--string); + } + .function { + color: var(--function); + } +} + +code.json{ + color: var(--code-fg); + .constant_builtin{ + color: var(--keyword); + } + span.string_special_key{ + color: var(--string) + } + .string{ + color: var(--function) + } +} + +@media (prefers-color-scheme: light) { + code{ + filter: brightness(0.8) contrast(1.5); + } +} diff --git a/book-src/images/logo.webp b/assets/images/logo.webp similarity index 100% rename from book-src/images/logo.webp rename to assets/images/logo.webp diff --git a/book-src/images/websocket-client.webp b/assets/images/websocket-client.webp similarity index 100% rename from book-src/images/websocket-client.webp rename to assets/images/websocket-client.webp diff --git a/src/01-01.zig b/assets/src/01-01.zig similarity index 100% rename from src/01-01.zig rename to assets/src/01-01.zig diff --git a/src/01-02.zig b/assets/src/01-02.zig similarity index 100% rename from src/01-02.zig rename to assets/src/01-02.zig diff --git a/src/01-03.zig b/assets/src/01-03.zig similarity index 100% rename from src/01-03.zig rename to assets/src/01-03.zig diff --git a/src/01-04.zig b/assets/src/01-04.zig similarity index 100% rename from src/01-04.zig rename to assets/src/01-04.zig diff --git a/src/01-05.zig b/assets/src/01-05.zig similarity index 100% rename from src/01-05.zig rename to assets/src/01-05.zig diff --git a/src/02-01.zig b/assets/src/02-01.zig similarity index 100% rename from src/02-01.zig rename to assets/src/02-01.zig diff --git a/src/02-02.zig b/assets/src/02-02.zig similarity index 100% rename from src/02-02.zig rename to assets/src/02-02.zig diff --git a/src/03-01.zig b/assets/src/03-01.zig similarity index 100% rename from src/03-01.zig rename to assets/src/03-01.zig diff --git a/src/04-01.zig b/assets/src/04-01.zig similarity index 100% rename from src/04-01.zig rename to assets/src/04-01.zig diff --git a/src/04-02.zig b/assets/src/04-02.zig similarity index 100% rename from src/04-02.zig rename to assets/src/04-02.zig diff --git a/src/04-03.zig b/assets/src/04-03.zig similarity index 100% rename from src/04-03.zig rename to assets/src/04-03.zig diff --git a/src/05-01.zig b/assets/src/05-01.zig similarity index 100% rename from src/05-01.zig rename to assets/src/05-01.zig diff --git a/src/05-02.zig b/assets/src/05-02.zig similarity index 100% rename from src/05-02.zig rename to assets/src/05-02.zig diff --git a/src/05-03.zig b/assets/src/05-03.zig similarity index 100% rename from src/05-03.zig rename to assets/src/05-03.zig diff --git a/src/06-01.zig b/assets/src/06-01.zig similarity index 100% rename from src/06-01.zig rename to assets/src/06-01.zig diff --git a/src/07-01.zig b/assets/src/07-01.zig similarity index 100% rename from src/07-01.zig rename to assets/src/07-01.zig diff --git a/src/07-02.zig b/assets/src/07-02.zig similarity index 100% rename from src/07-02.zig rename to assets/src/07-02.zig diff --git a/src/07-03.zig b/assets/src/07-03.zig similarity index 100% rename from src/07-03.zig rename to assets/src/07-03.zig diff --git a/src/07-04.zig b/assets/src/07-04.zig similarity index 100% rename from src/07-04.zig rename to assets/src/07-04.zig diff --git a/src/08-01.zig b/assets/src/08-01.zig similarity index 100% rename from src/08-01.zig rename to assets/src/08-01.zig diff --git a/src/08-02.zig b/assets/src/08-02.zig similarity index 100% rename from src/08-02.zig rename to assets/src/08-02.zig diff --git a/src/09-01.zig b/assets/src/09-01.zig similarity index 100% rename from src/09-01.zig rename to assets/src/09-01.zig diff --git a/src/10-01.zig b/assets/src/10-01.zig similarity index 100% rename from src/10-01.zig rename to assets/src/10-01.zig diff --git a/src/10-02.zig b/assets/src/10-02.zig similarity index 100% rename from src/10-02.zig rename to assets/src/10-02.zig diff --git a/src/10-03.zig b/assets/src/10-03.zig similarity index 100% rename from src/10-03.zig rename to assets/src/10-03.zig diff --git a/src/11-01.zig b/assets/src/11-01.zig similarity index 100% rename from src/11-01.zig rename to assets/src/11-01.zig diff --git a/src/12-01.zig b/assets/src/12-01.zig similarity index 100% rename from src/12-01.zig rename to assets/src/12-01.zig diff --git a/src/12-02.zig b/assets/src/12-02.zig similarity index 100% rename from src/12-02.zig rename to assets/src/12-02.zig diff --git a/src/12-03.zig b/assets/src/12-03.zig similarity index 100% rename from src/12-03.zig rename to assets/src/12-03.zig diff --git a/src/13-01.zig b/assets/src/13-01.zig similarity index 100% rename from src/13-01.zig rename to assets/src/13-01.zig diff --git a/src/14-01.zig b/assets/src/14-01.zig similarity index 100% rename from src/14-01.zig rename to assets/src/14-01.zig diff --git a/src/14-02.zig b/assets/src/14-02.zig similarity index 100% rename from src/14-02.zig rename to assets/src/14-02.zig diff --git a/src/14-03.zig b/assets/src/14-03.zig similarity index 100% rename from src/14-03.zig rename to assets/src/14-03.zig diff --git a/src/15-01.zig b/assets/src/15-01.zig similarity index 100% rename from src/15-01.zig rename to assets/src/15-01.zig diff --git a/src/15-02.zig b/assets/src/15-02.zig similarity index 100% rename from src/15-02.zig rename to assets/src/15-02.zig diff --git a/assets/style.css b/assets/style.css new file mode 100644 index 0000000..d5bfde4 --- /dev/null +++ b/assets/style.css @@ -0,0 +1,294 @@ +:root { + /* TODO */ + --bg: #fff; + --fg: #111; + --border: #aaa; + --link: #0070f3; + --mobile-header-height: 3.25rem; + --toc-width: 20rem; + --toc-gap: 1rem; +} +@media (prefers-color-scheme: dark) { + :root { + --bg: #181818; + --fg: #eee; + --border: #444; + --link: #4ea1ff; + } +} + +p:has(+ pre) { + margin-bottom: 0; +} + +pre { + overflow: auto; + padding: 4px 5px; + background: #8888880a; + line-height: 1; +} + +pre:has(+ pre) { + margin-bottom: 10px; +} + +pre code { + tab-size: 4; + -moz-tab-size: 4; +} + +code { + font-family: monospace; + font-size: 14px; +} + +.center { + display: flex; + justify-content: center; + align-items: center; +} +.large { + font-size: 2rem; + line-height: 2; +} +.bold { + font-weight: bold; +} + +body { + /* margin: 20px auto; + max-width: 70vw; */ + line-height: 1.4; + font-size: 1.2rem; + background: var(--bg); + color: var(--fg); +} +@media screen and (max-width: 800px) { + body { + max-width: 93vw; + } +} + +#prev-next { + display: flex; + justify-content: space-between; + flex-wrap: wrap; + align-items: center; + margin-top: 20px; + padding-top: 5px; + border-top: 2px solid var(--border); +} + +#prev-next a { + text-decoration: none; +} +#prev-next > :last-child { + margin-left: auto; + text-align: right; +} +#prev-next > :first-child span::before { + content: "←"; +} + +#prev-next > :last-child span::after { + content: "→"; +} + +a { + color: inherit; + line-break: anywhere; + display: inline-block; +} + +image, +img { + max-width: 100%; + display: block; +} + +figure { + margin: 1rem; +} + +::-webkit-scrollbar { + width: 10px; + height: 10px; + background: var(--bg); +} +::-webkit-scrollbar-thumb { + background: #ccc; + border-radius: 8px; + border: 2px solid var(--bg); + min-height: 40px; +} +::-webkit-scrollbar-thumb:hover { + background: #bbb; +} +::-webkit-scrollbar-corner { + background: var(--bg); +} + +@media (prefers-color-scheme: dark) { + ::-webkit-scrollbar { + background: var(--bg); + } + ::-webkit-scrollbar-thumb { + background: #444; + border: 2px solid var(--bg); + } + ::-webkit-scrollbar-thumb:hover { + background: #555; + } + ::-webkit-scrollbar-corner { + background: var(--bg); + } +} + +html { + scrollbar-width: thin; + scrollbar-color: #ccc var(--bg); +} +@media (prefers-color-scheme: dark) { + html { + scrollbar-color: #444 var(--bg); + } +} + +.body { + padding-left: calc(var(--toc-width) + var(--toc-gap)); + box-sizing: border-box; +} + +.content { + margin-inline-start: auto; + margin-inline-end: auto; + max-width: 50rem; +} + +.toc { + width: var(--toc-width); + min-width: var(--toc-width); + word-break: keep-all; + position: fixed; + top: 0; + bottom: 0; + overflow-y: scroll; + /* word-break: normal; */ +} +.toc a { + text-decoration: none; + line-break: auto; +} + +.toc a:hover { + text-decoration: underline; +} + +.toc a[aria-current="page"] { + color: var(--link); + font-weight: bold; +} + +.toc > ul { + padding-inline-start: 0; + counter-reset: cate; +} + +.toc > ul ul{ + padding-inline-start: 2rem; + counter-reset: sec; + counter-increment: cate; +} + +.toc > ul ul li { + list-style: none; + counter-increment: sec; +} + +.toc > ul ul li a::before { + content: counter(cate) "." counter(sec) ". "; +} + +.toc li { + list-style: none; + padding-inline-start: 0; +} + +@media screen and (max-width: 800px) { + .toc { + display: none; + } + .article { + padding-left: 0; + } +} + +.mobile-header { + display: none; +} + +@media screen and (max-width: 800px) { + .mobile-header { + position: fixed; + top: 0; + left: 0; + right: 0; + height: var(--mobile-header-height); + display: flex; + align-items: center; + gap: 12px; + padding: 0 12px; + background: var(--bg); + color: var(--fg); + border-bottom: 1px solid var(--border); + z-index: 1000; + } + #toc-toggle { + font-size: 1.25rem; + background: transparent; + color: inherit; + border: none; + padding: 8px; + cursor: pointer; + } + .mobile-header .brand { + text-decoration: none; + font-weight: bold; + } + .toc { + display: none; + position: fixed; + top: var(--mobile-header-height); + left: 0; + right: 0; + bottom: 0; + width: auto; + min-width: auto; + padding: 8px 12px; + background: var(--bg); + z-index: 999; + border-top: 1px solid var(--border); + overflow-y: auto; + } + body.toc-open .toc { + display: block; + } + .body { + padding-left: 0; + padding-top: calc(var(--mobile-header-height) + 8px); + } + body{ + line-height: 1.2; + font-size: 1rem; + } + h1 { + margin: 0; + } + .meta{ + margin-top: 5px; + } +} + +h1{ + margin-bottom: 0; +} \ No newline at end of file diff --git a/assets/toc.js b/assets/toc.js new file mode 100644 index 0000000..da4177f --- /dev/null +++ b/assets/toc.js @@ -0,0 +1,50 @@ +(function() { + var btn = document.getElementById('toc-toggle'); + if (!btn) return; + var body = document.getElementById('body'); + var toc = document.getElementById('toc'); + function closeToc() { + body.classList.remove('toc-open'); + btn.setAttribute('aria-expanded', 'false'); + } + + function markAndCenterActive() { + if (!toc) return; + var links = toc.querySelectorAll('a[href]'); + var currentPath = location.pathname.replace(/\/$/, ''); + var activeLink = null; + links.forEach(function(a) { + try { + var hrefPath = new URL(a.getAttribute('href'), location.origin).pathname.replace(/\/$/, ''); + if (hrefPath === currentPath) { + a.setAttribute('aria-current', 'page'); + activeLink = a; + } else { + a.removeAttribute('aria-current'); + } + } catch (_) { + // ignore malformed hrefs + } + }); + if (activeLink) { + var targetScrollTop = activeLink.offsetTop - (toc.clientHeight / 2) + (activeLink.offsetHeight / 2); + if (!isNaN(targetScrollTop)) toc.scrollTop = Math.max(0, targetScrollTop); + } + } + + btn.addEventListener('click', function() { + var isOpen = body.classList.toggle('toc-open'); + btn.setAttribute('aria-expanded', isOpen ? 'true' : 'false'); + if (isOpen) { + requestAnimationFrame(markAndCenterActive); + } + }); + if (toc) { + toc.addEventListener('click', function(e) { + var target = e.target; + if (target && target.tagName === 'A') closeToc(); + }); + } + // Initial mark and center on load (desktop) + markAndCenterActive(); +})(); \ No newline at end of file diff --git a/book-src/02-01-sha-digest.md b/book-src/02-01-sha-digest.md deleted file mode 100644 index 71c5a76..0000000 --- a/book-src/02-01-sha-digest.md +++ /dev/null @@ -1,7 +0,0 @@ -## Calculate SHA-256 digest of a file - -There are many crypto algorithm implementations in std, `sha256`, `md5` are supported out of box. - -```zig -{{#include ../src/02-01.zig }} -``` diff --git a/book-src/05-04-websocket-server.md b/book-src/05-04-websocket-server.md deleted file mode 100644 index 1afa6d3..0000000 --- a/book-src/05-04-websocket-server.md +++ /dev/null @@ -1,7 +0,0 @@ -## WebSocket - -This example demonstrates an echo server. - -```zig -{{#include ../src/05-04.zig }} -``` diff --git a/book-src/14-02-postgres.md b/book-src/14-02-postgres.md deleted file mode 100644 index 0d52219..0000000 --- a/book-src/14-02-postgres.md +++ /dev/null @@ -1,13 +0,0 @@ -# Postgres - -As with [previous section](./14-01-sqlite.md), here we introduce [libpq](https://www.postgresql.org/docs/16/libpq-example.html) interface directly, other than [wrapper package](https://github.com/tonis2/zig-postgres). - -Data models used in this demo are the same with the one used in [SQLite section](./14-01-sqlite.md). - -> Note: After executing a query with `PQexec` like functions, if there are returning results, check the result with `PGRES_TUPLES_OK`, otherwise `PGRES_COMMAND_OK` should be used. - -- - -```zig -{{#include ../src/14-02.zig }} -``` diff --git a/book-src/14-03-mysql.md b/book-src/14-03-mysql.md deleted file mode 100644 index 1882235..0000000 --- a/book-src/14-03-mysql.md +++ /dev/null @@ -1,17 +0,0 @@ -# MySQL - -As with [sqlite section](./14-01-sqlite.md), here we introduce [libmysqlclient](https://dev.mysql.com/doc/c-api/8.0/en/c-api-basic-interface-usage.html) interface directly. - -Data models are introduced [here](database.md). - -> Note: After executing a query with `mysql_real_query` like functions, if there are returning results, we must consume the result, otherwise we will get following error when we execute next query. - -``` -Commands out of sync; you can't run this command now -``` - -- - -```zig -{{#include ../src/14-03.zig }} -``` diff --git a/book-src/15-02-string.md b/book-src/15-02-string.md deleted file mode 100644 index 22b7b3c..0000000 --- a/book-src/15-02-string.md +++ /dev/null @@ -1,7 +0,0 @@ -# String Parsing - -## String to number/enum - -```zig -{{#include ../src/15-02.zig }} -``` diff --git a/book-src/SUMMARY.md b/book-src/SUMMARY.md deleted file mode 100644 index b1c53b7..0000000 --- a/book-src/SUMMARY.md +++ /dev/null @@ -1,83 +0,0 @@ -# Summary - -[Introduction](./intro.md) - -- [File System]() - - - [Read file line by line](./01-01-read-file-line-by-line.md) - - [Mmap file](./01-02-mmap-file.md) - - [Find Files modified in the last 24 hours](./01-03-file-modified-24h-ago.md) - - [Check file existence](./01-04-file-exists.md) - - [Iterate directory](./01-05-iterate-dir.md) - -- [Cryptography]() - - - [Calculate SHA-256 digest of a file](./02-01-sha-digest.md) - - [Salt and hash a password with PBKDF2](./02-02-pbkdf2.md) - -- [Date and Time]() - - - [Measure the elapsed time between two code sections](./03-01-elapsed-time.md) - -- [Network]() - - - [Listen on unused port TCP/IP](./04-01-tcp-server.md) - - [TCP Client](./04-02-tcp-client.md) - - [UDP Echo](./04-03-udp-echo.md) - -- [Web Programming]() - - - [HTTP Get](./05-01-http-get.md) - - [HTTP Post](./05-02-http-post.md) - - [HTTP Server(std)](./05-03-http-server-std.md) - -- [Algorithms]() - - - [Generate Random Values](./06-01-rand.md) - -- [Concurrency]() - - - [Explicit Threads](./07-01-spawn.md) - - [Shared Data](./07-02-shared-data.md) - - [Thread pool](./07-03-threadpool.md) - - [Run Once](./07-04-run-once.md) - -- [Operating System]() - - - [Processor](./08-01-cpu-count.md) - - [External Command](./08-02-external.md) - -- [Development Tools]() - - - [Versioning](./09-01-semver.md) - -- [Encoding]() - - - [(De)serialize JSON](./10-01-json.md) - - [(De)serialize Zon](./10-02-zon.md) - - [Encode and decode base64](./10-03-base64.md) - -- [Mathematics]() - - - [Complex Numbers](./11-01-complex-numbers.md) - -- [Data Structures]() - - - [Bitfield](./12-01-bitfield.md) - - [Singly Linked List](./12-02-singly-linked-list.md) - - [Doubly Linked List](./12-03-doubly-linked-list.md) - -- [Command line]() - - - [Argument Parsing](./13-01-argparse.md) - - [ANSI Terminal]() - -- [Database](database.md) - - - [SQLite](./14-01-sqlite.md) - - [Postgres](./14-02-postgres.md) - - [MySQL](./14-03-mysql.md) - -- [Text Processing]() - - [Regex Expressions](15-01-regex.md) - - [String Parsing](15-02-string.md) diff --git a/book-src/intro.md b/book-src/intro.md deleted file mode 100644 index 03da6cf..0000000 --- a/book-src/intro.md +++ /dev/null @@ -1,42 +0,0 @@ -# Zig Cookbook - -[![](https://img.shields.io/discord/1155469703846834187?label=Chat%20on%20Discord)](https://discord.gg/bAehMGPb2R) -[![](https://img.shields.io/github/stars/zigcc/zig-cookbook?style=square&color=#30a14e)](https://github.com/zigcc/zig-cookbook/stargazers) -[![](https://github.com/zigcc/zig-cookbook/actions/workflows/ci.yml/badge.svg)](https://github.com/zigcc/zig-cookbook/actions/workflows/ci.yml) -[![](https://github.com/zigcc/zig-cookbook/actions/workflows/pages.yml/badge.svg)](https://github.com/zigcc/zig-cookbook/actions/workflows/pages.yml) - -![Zig Cookbook Logo](./images/logo.webp) - -[Zig cookbook](https://github.com/zigcc/zig-cookbook) is a collection of simple Zig programs that demonstrate good practices to accomplish common programming tasks. - -> - Main branch tracks Zig 0.14.0 and master, and are tested on Linux and macOS via GitHub actions. -> - Earlier Zig support could be found in [other branches](https://github.com/zigcc/zig-cookbook/branches). - -# How to use - -[The website](https://cookbook.ziglang.cc/) is generated by [mdbook](https://rust-lang.github.io/mdBook/), `mdbook serve` will start a server at `http://localhost:3000` for preview. - -Each recipe is accompanied by an illustrative example named after its corresponding sequence number. These examples can be executed using the command `zig build run-{chapter-num}-{sequence-num}`, or `zig build run-all` to execute all. - -> ## Note -> Some recipes may depend on system libraries -> - Use `make install-deps` to install client libraries, and -> - `docker-compose up -d` to start required databases. - -# Contributing - -This cookbook is a work in progress, and we welcome contributions from the community. If you have a favorite recipe that you'd like to share, please submit a [pull request](https://github.com/zigcc/zig-cookbook/pulls). - -# Acknowledgment - -When working on zig-cookbook, we benefit a lot from several similar projects, thanks for their awesome work. - -- [Rust Cookbook](https://github.com/rust-lang-nursery/rust-cookbook) - -# Star History - -[![Star History Chart](https://api.star-history.com/svg?repos=zigcc/zig-cookbook&type=Date)](https://star-history.com/#zigcc/zig-cookbook&Date) - -# License - -The markdown files are licensed under [CC BY-NC-ND 4.0 DEED](https://creativecommons.org/licenses/by-nc-nd/4.0/), and zig files are under MIT. diff --git a/book.toml b/book.toml deleted file mode 100644 index 486e1f0..0000000 --- a/book.toml +++ /dev/null @@ -1,22 +0,0 @@ -[book] -authors = ["ZigCC "] -description = "Zig cookbook is a collection of simple Zig programs that demonstrate good practices to accomplish common programming tasks." -language = "en" -multilingual = false -src = "book-src" -title = "Zig cookbook" - -[output.html] -git-repository-url = "https://github.com/zigcc/zig-cookbook" -edit-url-template = "https://github.com/zigcc/zig-cookbook/edit/main/{path}" -additional-js = ["static/zig-hl.js", "static/giscus.js"] -additional-css = ["static/last-changed.css"] -# site-url = "zig-cookbook" - -[preprocessor.last-changed] -command = "mdbook-last-changed" -renderer = ["html"] - - -[build] -create-missing = false diff --git a/build.zig b/build.zig index e203d61..72d57f5 100644 --- a/build.zig +++ b/build.zig @@ -10,7 +10,7 @@ pub fn build(b: *std.Build) !void { } fn addExample(b: *std.Build, run_all: *std.Build.Step) !void { - const src_dir = try fs.cwd().openDir(b.path("src").getPath(b), .{ .iterate = true }); + const src_dir = try fs.cwd().openDir(b.path("assets/src").getPath(b), .{ .iterate = true }); const target = b.standardTargetOptions(.{}); var it = src_dir.iterate(); @@ -22,7 +22,7 @@ fn addExample(b: *std.Build, run_all: *std.Build.Step) !void { const name = std.mem.trimRight(u8, entry.name, ".zig"); const exe = b.addExecutable(.{ .name = try allocPrint(b.allocator, "examples-{s}", .{name}), - .root_source_file = b.path(try allocPrint(b.allocator, "src/{s}.zig", .{name})), + .root_source_file = b.path(try allocPrint(b.allocator, "assets/src/{s}.zig", .{name})), .target = target, .optimize = .Debug, }); diff --git a/layouts/section.shtml b/layouts/section.shtml new file mode 100644 index 0000000..f5a7eae --- /dev/null +++ b/layouts/section.shtml @@ -0,0 +1,33 @@ + + + + + +
+ + +
+
+ +
+
+
+
+

+
+
+
+
+ + + +
+
+ + + +
+
+
+
+ \ No newline at end of file diff --git a/layouts/templates/base.shtml b/layouts/templates/base.shtml new file mode 100644 index 0000000..a260d01 --- /dev/null +++ b/layouts/templates/base.shtml @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/book-src/01-01-read-file-line-by-line.md b/src/01-01-read-file-line-by-line.smd similarity index 59% rename from book-src/01-01-read-file-line-by-line.md rename to src/01-01-read-file-line-by-line.smd index d3b9b97..812e3cb 100644 --- a/book-src/01-01-read-file-line-by-line.md +++ b/src/01-01-read-file-line-by-line.smd @@ -1,9 +1,12 @@ -# Read file line by line +--- +.title = "Read file line by line", +.date = "2024-01-01", +.author = "ZigCC", +.layout = "section.shtml", +--- There is a [`Reader`] type in Zig, which provides various methods to read file, such as `readAll`, `readInt`. Here we will use `streamUntilDelimiter` to split lines. -```zig -{{#include ../src/01-01.zig }} -``` +[]($code.siteAsset('src/01-01.zig').language('zig')) [`reader`]: https://ziglang.org/documentation/0.14.0/std/#std.io.Reader diff --git a/book-src/01-02-mmap-file.md b/src/01-02-mmap-file.smd similarity index 63% rename from book-src/01-02-mmap-file.md rename to src/01-02-mmap-file.smd index f30ec7e..ec9f76c 100644 --- a/book-src/01-02-mmap-file.md +++ b/src/01-02-mmap-file.smd @@ -1,7 +1,10 @@ -# Mmap file +--- +.title = "Mmap file", +.date = "2024-01-01", +.author = "ZigCC", +.layout = "section.shtml", +--- Creates a memory map of a file using [mmap](https://man7.org/linux/man-pages/man2/mmap.2.html) and simulates some non-sequential reads from the file. Using a memory map means you just index into a slice rather than having to deal with seek to navigate a file. -```zig -{{#include ../src/01-02.zig }} -``` +[]($code.siteAsset('src/01-02.zig').language('zig')) diff --git a/book-src/01-03-file-modified-24h-ago.md b/src/01-03-file-modified-24h-ago.smd similarity index 56% rename from book-src/01-03-file-modified-24h-ago.md rename to src/01-03-file-modified-24h-ago.smd index e04752a..a4121d5 100644 --- a/book-src/01-03-file-modified-24h-ago.md +++ b/src/01-03-file-modified-24h-ago.smd @@ -1,9 +1,12 @@ -# Find files that have been modified in the last 24 hours +--- +.title = "Find files that have been modified in the last 24 hours", +.date = "2024-01-01", +.author = "ZigCC", +.layout = "section.shtml", +--- Gets the current working directory by calling `fs.cwd()`, and then iterates files using `walk()`, which will recursively iterate entries in the directory. For each entry, we check if it's a file, and use `statFile()` to retrieve the file's metadata. -```zig -{{#include ../src/01-03.zig }} -``` +[]($code.siteAsset('src/01-03.zig').language('zig')) diff --git a/book-src/01-04-file-exists.md b/src/01-04-file-exists.smd similarity index 78% rename from book-src/01-04-file-exists.md rename to src/01-04-file-exists.smd index 1c9a592..999b3f9 100644 --- a/book-src/01-04-file-exists.md +++ b/src/01-04-file-exists.smd @@ -1,10 +1,13 @@ -# Check file existence +--- +.title = "Check file existence", +.date = "2024-01-01", +.author = "ZigCC", +.layout = "section.shtml", +--- In this example, `access` is utilized to verify file existence; however, for it to function correctly, one must specifically check for the `FileNotFound` error type. -```zig -{{#include ../src/01-04.zig}} -``` +[]($code.siteAsset('src/01-04.zig').language('zig')) However, there is a gotcha described in [its documentation](https://github.com/ziglang/zig/blob/0.13.0/lib/std/fs/Dir.zig#L2390-L2396): diff --git a/book-src/01-05-iterate-dir.md b/src/01-05-iterate-dir.smd similarity index 66% rename from book-src/01-05-iterate-dir.md rename to src/01-05-iterate-dir.smd index 4d20004..6a5d7dd 100644 --- a/book-src/01-05-iterate-dir.md +++ b/src/01-05-iterate-dir.smd @@ -1,9 +1,13 @@ -## Iterate directory +--- +.title = "Iterate directory", +.date = "2024-01-01", +.author = "ZigCC", +.layout = "section.shtml", +--- +Iterate directory There is a convenient method `walk` for this purpose, it will walk the directory iteratively. -```zig -{{#include ../src/01-05.zig}} -``` +[]($code.siteAsset('src/01-05.zig').language('zig')) The order of returned file system entries is undefined, if there are any requirements for the order in which to return the entries, such as alphabetical or chronological, sort them accordingly. Otherwise, leave them in their original, unsorted order. diff --git a/src/02-01-sha-digest.smd b/src/02-01-sha-digest.smd new file mode 100644 index 0000000..d7c0739 --- /dev/null +++ b/src/02-01-sha-digest.smd @@ -0,0 +1,11 @@ +--- +.title = "Calculate SHA-256 digest of a file", +.date = "2024-01-01", +.author = "ZigCC", +.layout = "section.shtml", +--- +Calculate SHA-256 digest of a file + +There are many crypto algorithm implementations in std, `sha256`, `md5` are supported out of box. + +[]($code.siteAsset('src/02-01.zig').language('zig')) diff --git a/book-src/02-02-pbkdf2.md b/src/02-02-pbkdf2.smd similarity index 63% rename from book-src/02-02-pbkdf2.md rename to src/02-02-pbkdf2.smd index 0fecab5..fd4790f 100644 --- a/book-src/02-02-pbkdf2.md +++ b/src/02-02-pbkdf2.smd @@ -1,12 +1,16 @@ -## Salt and hash a password with PBKDF2 +--- +.title = "Salt and hash a password with PBKDF2", +.date = "2024-01-01", +.author = "ZigCC", +.layout = "section.shtml", +--- +Salt and hash a password with PBKDF2 Uses [`std.crypto.pwhash.pbkdf2`] to hash a salted password. The salt is generated using [`std.rand.DefaultPrng`], which fills the salt byte array with generated random numbers. -```zig -{{#include ../src/02-02.zig }} -``` +[]($code.siteAsset('src/02-02.zig').language('zig')) [`std.crypto.pwhash.pbkdf2`]: https://ziglang.org/documentation/0.11.0/std/#A;std:crypto.pwhash.pbkdf2 [`std.rand.defaultprng`]: https://ziglang.org/documentation/0.11.0/std/#A;std:rand.DefaultPrng diff --git a/book-src/03-01-elapsed-time.md b/src/03-01-elapsed-time.smd similarity index 74% rename from book-src/03-01-elapsed-time.md rename to src/03-01-elapsed-time.smd index 9df9da1..aadf43e 100644 --- a/book-src/03-01-elapsed-time.md +++ b/src/03-01-elapsed-time.smd @@ -1,4 +1,9 @@ -### Measure the elapsed time between two code sections +--- +.title = "Measure the elapsed time between two code sections", +.date = "2024-01-01", +.author = "ZigCC", +.layout = "section.shtml", +--- [`Instant`] represents a timestamp with respect to the currently executing program that ticks while the program is suspended and can be used to record elapsed time. @@ -6,9 +11,7 @@ Calling [`std.time.Instant.since`] returns a u64 representing nanoseconds elapse This is such a common task, that there is a [`Timer`] for convenience. -```zig -{{#include ../src/03-01.zig }} -``` +[]($code.siteAsset('src/03-01.zig').language('zig')) [`instant`]: https://ziglang.org/documentation/0.11.0/std/#A;std:time.Instant [`timer`]: https://ziglang.org/documentation/0.11.0/std/#A;std:time.Timer diff --git a/book-src/04-01-tcp-server.md b/src/04-01-tcp-server.smd similarity index 79% rename from book-src/04-01-tcp-server.md rename to src/04-01-tcp-server.smd index e405719..0d519de 100644 --- a/book-src/04-01-tcp-server.md +++ b/src/04-01-tcp-server.smd @@ -1,12 +1,15 @@ -## Listen on unused port TCP/IP +--- +.title = "Listen on unused port TCP/IP", +.date = "2024-01-01", +.author = "ZigCC", +.layout = "section.shtml", +--- In this example, the port is displayed on the console, and the program will listen until a request is made. `Ip4Address` assigns a random port when setting port to 0. -```zig -{{#include ../src/04-01.zig }} -``` +[]($code.siteAsset('src/04-01.zig').language('zig')) When start starts up, try test like this: diff --git a/book-src/04-02-tcp-client.md b/src/04-02-tcp-client.smd similarity index 67% rename from book-src/04-02-tcp-client.md rename to src/04-02-tcp-client.smd index aacface..0dd1cc0 100644 --- a/book-src/04-02-tcp-client.md +++ b/src/04-02-tcp-client.smd @@ -1,11 +1,14 @@ -## TCP Client +--- +.title = "TCP Client", +.date = "2024-01-01", +.author = "ZigCC", +.layout = "section.shtml", +--- In this example, we demonstrate creation of a TCP client to connect to the server from the previous section. You can run it using `zig build run-04-02 -- `. -```zig -{{#include ../src/04-02.zig }} -``` +[]($code.siteAsset('src/04-02.zig').language('zig')) By default, the program connects with IPv4. If you want IPv6, use `::1` instead of `127.0.0.1`, replace `net.Address.parseIp4` by diff --git a/book-src/04-03-udp-echo.md b/src/04-03-udp-echo.smd similarity index 76% rename from book-src/04-03-udp-echo.md rename to src/04-03-udp-echo.smd index 1d059c3..75fbed4 100644 --- a/book-src/04-03-udp-echo.md +++ b/src/04-03-udp-echo.smd @@ -1,4 +1,9 @@ -## UDP Echo +--- +.title = "UDP Echo", +.date = "2024-01-01", +.author = "ZigCC", +.layout = "section.shtml", +--- Similar to the TCP server example, this program will listen on the specified IP address and port, but for UDP datagrams this time. If data is received, @@ -7,9 +12,7 @@ it will be echoed back to the sender's address. Although `std.net` is mostly focused on abstractions for TCP (so far), we can still make use of socket programming to communicate via UDP. -```zig -{{#include ../src/04-03.zig }} -``` +[]($code.siteAsset('src/04-03.zig').language('zig')) After starting the program, test as follows with `nc`, using the `-u` flag for UDP: diff --git a/book-src/05-01-http-get.md b/src/05-01-http-get.smd similarity index 78% rename from book-src/05-01-http-get.md rename to src/05-01-http-get.smd index 645c876..9a70e81 100644 --- a/book-src/05-01-http-get.md +++ b/src/05-01-http-get.smd @@ -1,4 +1,9 @@ -## GET +--- +.title = "GET", +.date = "2024-01-01", +.author = "ZigCC", +.layout = "section.shtml", +--- Parses the supplied URL and makes a synchronous HTTP GET request with [`request`]. Prints obtained [`Response`] status and headers. @@ -6,9 +11,7 @@ with [`request`]. Prints obtained [`Response`] status and headers. > Note: Since HTTP support is in early stage, it's recommended to use [libcurl](https://curl.se/libcurl/c/) for any complex task. > And when the buffer is not enough, it will return `error.HttpHeadersOverSize` -```zig -{{#include ../src/05-01.zig }} -``` +[]($code.siteAsset('src/05-01.zig').language('zig')) [`request`]: https://ziglang.org/documentation/0.11.0/std/src/std/http/Client.zig.html#L992 [`response`]: https://ziglang.org/documentation/0.11.0/std/src/std/http/Client.zig.html#L322 diff --git a/book-src/05-02-http-post.md b/src/05-02-http-post.smd similarity index 76% rename from book-src/05-02-http-post.md rename to src/05-02-http-post.smd index 77be573..323b830 100644 --- a/book-src/05-02-http-post.md +++ b/src/05-02-http-post.smd @@ -1,13 +1,16 @@ -## POST +--- +.title = "POST", +.date = "2024-01-01", +.author = "ZigCC", +.layout = "section.shtml", +--- Parses the supplied URL and makes a synchronous HTTP POST request with [`request`]. Prints obtained [`Response`] status, and data received from server. > Note: Since HTTP support is in early stage, it's recommended to use [libcurl](https://curl.se/libcurl/c/) for any complex task. -```zig -{{#include ../src/05-02.zig }} -``` +[]($code.siteAsset('src/05-02.zig').language('zig')) [`request`]: https://ziglang.org/documentation/0.11.0/std/src/std/http/Client.zig.html#L992 [`response`]: https://ziglang.org/documentation/0.11.0/std/src/std/http/Client.zig.html#L322 diff --git a/book-src/05-03-http-server-std.md b/src/05-03-http-server-std.smd similarity index 85% rename from book-src/05-03-http-server-std.md rename to src/05-03-http-server-std.smd index bc131b6..aa14c7d 100644 --- a/book-src/05-03-http-server-std.md +++ b/src/05-03-http-server-std.smd @@ -1,4 +1,9 @@ -## http.Server - std +--- +.title = "http.Server - std", +.date = "2024-01-01", +.author = "ZigCC", +.layout = "section.shtml", +--- A basic implementation of `http.Server` has been introduced since Zig 0.12.0. @@ -8,9 +13,7 @@ For each connection we spawn a new thread to handle it, in `accept` it will: 3. For each request, we first check if it could upgrade to WebSocket. - If it succeeds, call `serveWebSocket` else call `serverHTTP` -```zig -{{#include ../src/05-03.zig }} -``` +[]($code.siteAsset('src/05-03.zig').language('zig')) ## Test @@ -38,7 +41,7 @@ Then we could send message like this: webSocket.send('abc') ``` -![](./images/websocket-client.webp) +[websocket-client]($image.siteAsset('images/websocket-client.webp')) See [Writing WebSocket client applications - Web APIs | MDN](https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API/Writing_WebSocket_client_applications) for details. diff --git a/book-src/06-01-rand.md b/src/06-01-rand.smd similarity index 58% rename from book-src/06-01-rand.md rename to src/06-01-rand.smd index 2c9465b..8f2c711 100644 --- a/book-src/06-01-rand.md +++ b/src/06-01-rand.smd @@ -1,9 +1,12 @@ -## Generate random numbers +--- +.title = "Generate random numbers", +.date = "2024-01-01", +.author = "ZigCC", +.layout = "section.shtml", +--- Generates random numbers with the help of a thread-local, cryptographically secure pseudo random number generator [`std.crypto.random`]. -```zig -{{#include ../src/06-01.zig }} -``` +[]($code.siteAsset('src/06-01.zig').language('zig')) [`std.crypto.random`]: https://ziglang.org/documentation/0.11.0/std/#A;std:crypto.random diff --git a/book-src/07-01-spawn.md b/src/07-01-spawn.smd similarity index 75% rename from book-src/07-01-spawn.md rename to src/07-01-spawn.smd index 7237863..48aaa0a 100644 --- a/book-src/07-01-spawn.md +++ b/src/07-01-spawn.smd @@ -1,4 +1,9 @@ -## Spawn a short-lived thread +--- +.title = "Spawn a short-lived thread", +.date = "2024-01-01", +.author = "ZigCC", +.layout = "section.shtml", +--- The example uses [`std.Thread`] for concurrent and parallel programming. [`std.Thread.spawn`] spawns a new thread to calculate the result. @@ -7,9 +12,7 @@ This example splits the array in half and performs the work in separate threads. > Note: In order to ensure `t1` thread is completed when spawn `t2` fails, we `defer t1.join()` immediately after spawn `t1`. -```zig -{{#include ../src/07-01.zig }} -``` +[]($code.siteAsset('src/07-01.zig').language('zig')) [`std.thread`]: https://ziglang.org/documentation/0.11.0/std/#A;std:Thread [`std.thread.spawn`]: https://ziglang.org/documentation/0.11.0/std/#A;std:Thread.spawn diff --git a/book-src/07-02-shared-data.md b/src/07-02-shared-data.smd similarity index 65% rename from book-src/07-02-shared-data.md rename to src/07-02-shared-data.smd index 5c96680..2afa1d4 100644 --- a/book-src/07-02-shared-data.md +++ b/src/07-02-shared-data.smd @@ -1,10 +1,13 @@ -## Share data between two threads +--- +.title = "Share data between two threads", +.date = "2024-01-01", +.author = "ZigCC", +.layout = "section.shtml", +--- When we want to mutate data shared between threads, [`Mutex`](**Mut**ually **ex**clusive flag) must be used to synchronize threads, otherwise the result maybe unexpected. -```zig -{{#include ../src/07-02.zig}} -``` +[]($code.siteAsset('src/07-02.zig').language('zig')) If we remove Mutex protection, the result will most like be less than 30,000. [`Mutex`]: https://ziglang.org/documentation/0.11.0/std/#A;std:Thread.Mutex diff --git a/book-src/07-03-threadpool.md b/src/07-03-threadpool.smd similarity index 73% rename from book-src/07-03-threadpool.md rename to src/07-03-threadpool.smd index 92dcfb0..2218c1a 100644 --- a/book-src/07-03-threadpool.md +++ b/src/07-03-threadpool.smd @@ -1,4 +1,9 @@ -## Thread pool +--- +.title = "Thread pool", +.date = "2024-01-01", +.author = "ZigCC", +.layout = "section.shtml", +--- Thread pools address two different problems: 1. They usually provide improved performance when executing large numbers of asynchronous tasks, due to reduced per-task invocation overhead, and @@ -7,6 +12,4 @@ Thread pools address two different problems: In this example, we spawn 10 tasks into thread pool, and use `WaitGroup` to wait for them to finish. -```zig -{{#include ../src/07-03.zig}} -``` +[]($code.siteAsset('src/07-03.zig').language('zig')) diff --git a/book-src/07-04-run-once.md b/src/07-04-run-once.smd similarity index 62% rename from book-src/07-04-run-once.md rename to src/07-04-run-once.smd index b168a73..ce9ce3d 100644 --- a/book-src/07-04-run-once.md +++ b/src/07-04-run-once.smd @@ -1,7 +1,11 @@ -## Run Once +--- +.title = "Run Once", +.date = "2024-01-01", +.author = "ZigCC", +.layout = "section.shtml", +--- + `std.once` ensures a function executes exactly one time, regardless of how many threads attempt to call it or how many times it's invoked. This thread-safe initialization is particularly useful for singleton patterns and one-time setup operations. -```Zig -{{#include ../src/07-04.zig}} -``` +[]($code.siteAsset('src/07-04.zig').language('zig')) diff --git a/book-src/08-01-cpu-count.md b/src/08-01-cpu-count.smd similarity index 52% rename from book-src/08-01-cpu-count.md rename to src/08-01-cpu-count.smd index 7be7cf6..cfc185f 100644 --- a/book-src/08-01-cpu-count.md +++ b/src/08-01-cpu-count.smd @@ -1,9 +1,12 @@ -## Check number of logical cpu cores +--- +.title = "Check number of logical cpu cores", +.date = "2024-01-01", +.author = "ZigCC", +.layout = "section.shtml", +--- Shows the number of logical CPU cores in the current machine using [`std.Thread.getCpuCount`]. -```zig -{{#include ../src/08-01.zig }} -``` +[]($code.siteAsset('src/08-01.zig').language('zig')) [`std.thread.getcpucount`]: https://ziglang.org/documentation/0.11.0/std/#A;std:Thread.getCpuCount diff --git a/book-src/08-02-external.md b/src/08-02-external.smd similarity index 61% rename from book-src/08-02-external.md rename to src/08-02-external.smd index c618c17..e61c96e 100644 --- a/book-src/08-02-external.md +++ b/src/08-02-external.smd @@ -1,10 +1,13 @@ -# External Command +--- +.title = "External Command", +.date = "2024-01-01", +.author = "ZigCC", +.layout = "section.shtml", +--- Run an external command via [`std.process.Child`], and collect output into `ArrayList` via [pipe]. -```zig -{{#include ../src/08-02.zig }} -``` +[]($code.siteAsset('src/08-02.zig').language('zig')) [`std.process.child`]: https://ziglang.org/documentation/0.11.0/std/#A;std:process.Child [pipe]: https://man7.org/linux/man-pages/man2/pipe.2.html diff --git a/book-src/09-01-semver.md b/src/09-01-semver.smd similarity index 67% rename from book-src/09-01-semver.md rename to src/09-01-semver.smd index 8608ea4..634acf9 100644 --- a/book-src/09-01-semver.md +++ b/src/09-01-semver.smd @@ -1,10 +1,13 @@ -## Parse a version string. +--- +.title = "Parse a version string.", +.date = "2024-01-01", +.author = "ZigCC", +.layout = "section.shtml", +--- Constructs a [`std.SemanticVersion`] from a string literal using [`SemanticVersion.parse`]. -```zig -{{#include ../src/09-01.zig }} -``` +[]($code.siteAsset('src/09-01.zig').language('zig')) [`std.semanticversion`]: https://ziglang.org/documentation/0.11.0/std/#A;std:SemanticVersion [`semanticversion.parse`]: https://ziglang.org/documentation/0.11.0/std/#A;std:SemanticVersion.parse diff --git a/book-src/10-01-json.md b/src/10-01-json.smd similarity index 80% rename from book-src/10-01-json.md rename to src/10-01-json.smd index d6a2455..cdbc260 100644 --- a/book-src/10-01-json.md +++ b/src/10-01-json.smd @@ -1,4 +1,9 @@ -## Serialize and deserialize JSON +--- +.title = "Serialize and deserialize JSON", +.date = "2024-01-01", +.author = "ZigCC", +.layout = "section.shtml", +--- The [`std.json`] provides a set of functions such as [`stringify`] and [`stringifyAlloc`] for serializing JSON. Additionally, we can use [`parseFromSlice`] function to parse a `[]u8` of JSON. @@ -6,9 +11,7 @@ Additionally, we can use [`parseFromSlice`] function to parse a `[]u8` of JSON. The example below shows a `[]u8` of JSON being parsed. Compare each member one by one. Then, we modify the `verified` field to `false` and serialize it back into a JSON string. -```zig -{{#include ../src/10-01.zig }} -``` +[]($code.siteAsset('src/10-01.zig').language('zig')) [`std.json`]: https://ziglang.org/documentation/0.11.0/std/#A;std:json [`stringify`]: https://ziglang.org/documentation/0.11.0/std/#A;std:json.stringify diff --git a/book-src/10-02-zon.md b/src/10-02-zon.smd similarity index 70% rename from book-src/10-02-zon.md rename to src/10-02-zon.smd index 7e09701..73a4d36 100644 --- a/book-src/10-02-zon.md +++ b/src/10-02-zon.smd @@ -1,4 +1,9 @@ -## Serialize and deserialize Zon +--- +.title = "Serialize and deserialize Zon", +.date = "2024-01-01", +.author = "ZigCC", +.layout = "section.shtml", +--- ZON ("Zig Object Notation") is a textual file format. Outside of `nan` and `inf` literals, ZON's grammar is a subset of Zig's. @@ -15,6 +20,4 @@ Supported Zig primitives: * anonymous struct literals * anonymous tuple literals -```zig -{{#include ../src/10-02.zig }} -``` +[]($code.siteAsset('src/10-02.zig').language('zig')) diff --git a/book-src/10-03-base64.md b/src/10-03-base64.smd similarity index 74% rename from book-src/10-03-base64.md rename to src/10-03-base64.smd index 1c8a011..abb6a63 100644 --- a/book-src/10-03-base64.md +++ b/src/10-03-base64.smd @@ -1,11 +1,14 @@ -## Encode and decode base64 +--- +.title = "Encode and decode base64", +.date = "2024-01-01", +.author = "ZigCC", +.layout = "section.shtml", +--- Encodes a byte slice into `base64` string using [`std.base64.standard`] [`encode`] and decodes it with [`standard`] [`decode`]. -```zig -{{#include ../src/10-02.zig }} -``` +[]($code.siteAsset('src/10-02.zig').language('zig')) [`std.base64.standard`]: https://ziglang.org/documentation/0.11.0/std/#A;std:base64.standard [`standard`]: https://ziglang.org/documentation/0.11.0/std/src/std/base64.zig.html#L29 diff --git a/book-src/11-01-complex-numbers.md b/src/11-01-complex-numbers.smd similarity index 68% rename from book-src/11-01-complex-numbers.md rename to src/11-01-complex-numbers.smd index 1778731..6a693bc 100644 --- a/book-src/11-01-complex-numbers.md +++ b/src/11-01-complex-numbers.smd @@ -1,4 +1,9 @@ -## Creating and adding complex numbers +--- +.title = "Creating and adding complex numbers", +.date = "2024-01-01", +.author = "ZigCC", +.layout = "section.shtml", +--- Creates complex numbers of type [`std.math.Complex`]. Both the real and imaginary part of the complex number must be of the same type. @@ -7,8 +12,6 @@ Performing mathematical operations on complex numbers is the same as on built in types: the numbers in question must be of the same type (i.e. floats or integers). -```zig -{{#include ../src/11-01.zig }} -``` +[]($code.siteAsset('src/11-01.zig').language('zig')) [`std.math.complex`]: https://ziglang.org/documentation/0.11.0/std/#A;std:math.Complex diff --git a/book-src/12-01-bitfield.md b/src/12-01-bitfield.smd similarity index 79% rename from book-src/12-01-bitfield.md rename to src/12-01-bitfield.smd index 185ec9e..8e0e446 100644 --- a/book-src/12-01-bitfield.md +++ b/src/12-01-bitfield.smd @@ -1,12 +1,15 @@ -# Bitfield +--- +.title = "Bitfield", +.date = "2024-01-01", +.author = "ZigCC", +.layout = "section.shtml", +--- The fields of a [packed struct](https://ziglang.org/documentation/master/#packed-struct) are always laid out in memory in the order they are written, with no padding, so they are very nice to represent a bitfield. Boolean values are represented as 1 bit in a packed struct, Zig also has arbitrary bit-width integers, like u28, u1 and so on. -```zig -{{#include ../src/12-01.zig }} -``` +[]($code.siteAsset('src/12-01.zig').language('zig')) ## Reference diff --git a/book-src/12-02-singly-linked-list.md b/src/12-02-singly-linked-list.smd similarity index 73% rename from book-src/12-02-singly-linked-list.md rename to src/12-02-singly-linked-list.smd index 4b41e08..2d2ab96 100644 --- a/book-src/12-02-singly-linked-list.md +++ b/src/12-02-singly-linked-list.smd @@ -1,4 +1,9 @@ -# Singly Linked List +--- +.title = "Singly Linked List", +.date = "2024-01-01", +.author = "ZigCC", +.layout = "section.shtml", +--- [Singly linked list] contains nodes linked together. The list contains: - `head`, head of the list, used for traversal. @@ -10,8 +15,6 @@ Operations that can be performed on singly linked lists include: - Deletion O(n), which is the most complex since it needs to maintain head/tail pointer. - Traversal O(n) -```zig -{{#include ../src/12-02.zig }} -``` +[]($code.siteAsset('src/12-02.zig').language('zig')) [Singly linked list]: https://en.wikipedia.org/wiki/Linked_list diff --git a/book-src/12-03-doubly-linked-list.md b/src/12-03-doubly-linked-list.smd similarity index 86% rename from book-src/12-03-doubly-linked-list.md rename to src/12-03-doubly-linked-list.smd index 704df82..865af69 100644 --- a/book-src/12-03-doubly-linked-list.md +++ b/src/12-03-doubly-linked-list.smd @@ -1,4 +1,9 @@ -# Doubly Linked List +--- +.title = "Doubly Linked List", +.date = "2024-01-01", +.author = "ZigCC", +.layout = "section.shtml", +--- A [doubly linked list] contains nodes that are linked together in both directions, allowing for more efficient operations in some scenarios. Each node in a doubly linked list contains: - `data`, the value stored in the node. @@ -16,8 +21,6 @@ Operations that can be performed on doubly linked lists include: - Deletion O(n), with improved efficiency compared to singly linked lists it could easily find and remove nodes in this list without a full traversal. -```zig -{{#include ../src/12-03.zig }} -``` +[]($code.siteAsset('src/12-03.zig').language('zig')) [doubly linked list]: https://en.wikipedia.org/wiki/Doubly_linked_list diff --git a/book-src/13-01-argparse.md b/src/13-01-argparse.smd similarity index 69% rename from book-src/13-01-argparse.md rename to src/13-01-argparse.smd index 505d9aa..210d680 100644 --- a/book-src/13-01-argparse.md +++ b/src/13-01-argparse.smd @@ -1,4 +1,9 @@ -# Argument Parsing +--- +.title = "Argument Parsing", +.date = "2024-01-01", +.author = "ZigCC", +.layout = "section.shtml", +--- Parsing arguments is common in command line programs and there are some packages in Zig to make this task easier. To name a few: @@ -8,6 +13,4 @@ Parsing arguments is common in command line programs and there are some packages Here we will give an example using `simargs`. -```zig -{{#include ../src/13-01.zig }} -``` +[]($code.siteAsset('src/13-01.zig').language('zig')) diff --git a/book-src/14-01-sqlite.md b/src/14-01-sqlite.smd similarity index 53% rename from book-src/14-01-sqlite.md rename to src/14-01-sqlite.smd index 20d13c2..495ce22 100644 --- a/book-src/14-01-sqlite.md +++ b/src/14-01-sqlite.smd @@ -1,9 +1,12 @@ -# SQLite +--- +.title = "SQLite", +.date = "2024-01-01", +.author = "ZigCC", +.layout = "section.shtml", +--- Although there are some [wrapper package](https://github.com/vrischmann/zig-sqlite) options for SQLite in Zig, they are unstable. So here we will introduce the [C API interface](https://www.sqlite.org/cintro.html). -Data models are introduced [here](database.md). +Data models are introduced [here](database). -```zig -{{#include ../src/14-01.zig }} -``` +[]($code.siteAsset('src/14-01.zig').language('zig')) diff --git a/src/14-02-postgres.smd b/src/14-02-postgres.smd new file mode 100644 index 0000000..d9212d7 --- /dev/null +++ b/src/14-02-postgres.smd @@ -0,0 +1,16 @@ +--- +.title = "Postgres", +.date = "2024-01-01", +.author = "ZigCC", +.layout = "section.shtml", +--- + +As with [previous section](14-01-sqlite), here we introduce [libpq](https://www.postgresql.org/docs/16/libpq-example.html) interface directly, other than [wrapper package](https://github.com/tonis2/zig-postgres). + +Data models used in this demo are the same with the one used in [SQLite section](14-01-sqlite). + +> Note: After executing a query with `PQexec` like functions, if there are returning results, check the result with `PGRES_TUPLES_OK`, otherwise `PGRES_COMMAND_OK` should be used. + +- + +[]($code.siteAsset('src/14-02.zig').language('zig')) diff --git a/src/14-03-mysql.smd b/src/14-03-mysql.smd new file mode 100644 index 0000000..4d7e3d4 --- /dev/null +++ b/src/14-03-mysql.smd @@ -0,0 +1,20 @@ +--- +.title = "MySQL", +.date = "2024-01-01", +.author = "ZigCC", +.layout = "section.shtml", +--- + +As with [sqlite section](14-01-sqlite), here we introduce [libmysqlclient](https://dev.mysql.com/doc/c-api/8.0/en/c-api-basic-interface-usage.html) interface directly. + +Data models are introduced [here](database). + +> Note: After executing a query with `mysql_real_query` like functions, if there are returning results, we must consume the result, otherwise we will get following error when we execute next query. + +``` +Commands out of sync; you can't run this command now +``` + +- + +[]($code.siteAsset('src/14-03.zig').language('zig')) diff --git a/book-src/15-01-regex.md b/src/15-01-regex.smd similarity index 84% rename from book-src/15-01-regex.md rename to src/15-01-regex.smd index eceefc9..94e2db4 100644 --- a/book-src/15-01-regex.md +++ b/src/15-01-regex.smd @@ -1,4 +1,9 @@ -# Regular Expressions +--- +.title = "Regular Expressions", +.date = "2024-01-01", +.author = "ZigCC", +.layout = "section.shtml", +--- Currently there is no regex support in Zig, so the best way to go is binding with Posix's [regex.h](https://pubs.opengroup.org/onlinepubs/7908799/xsh/regex.h.html). @@ -11,9 +16,7 @@ void free_regex_t(regex_t* ptr); `regex_t*` is a pointer, it has fixed size, so we can use it directly in Zig. -```zig -{{#include ../src/15-01.zig }} -``` +[]($code.siteAsset('src/15-01.zig').language('zig')) ## References diff --git a/src/15-02-string.smd b/src/15-02-string.smd new file mode 100644 index 0000000..39ab693 --- /dev/null +++ b/src/15-02-string.smd @@ -0,0 +1,10 @@ +--- +.title = "String Parsing", +.date = "2024-01-01", +.author = "ZigCC", +.layout = "section.shtml", +--- + +## String to number/enum + +[]($code.siteAsset('src/15-02.zig').language('zig')) diff --git a/book-src/database.md b/src/database.smd similarity index 85% rename from book-src/database.md rename to src/database.smd index b4e111a..9c05059 100644 --- a/book-src/database.md +++ b/src/database.smd @@ -1,4 +1,10 @@ -# Database +--- +.title = "Database", +.date = "2024-01-01", +.author = "ZigCC", +.layout = "section.shtml", +--- + This section will demonstrate how to connect to popular databases from Zig. diff --git a/src/index.smd b/src/index.smd new file mode 100644 index 0000000..5e9020b --- /dev/null +++ b/src/index.smd @@ -0,0 +1,63 @@ +--- +.title = "introduction", +.date = "2024-01-01", +.author = "ZigCC", +.layout = "section.shtml", +--- + +```=html + + Chat on Discord + + + GitHub Stars + + + CI + + + Pages + +``` + +![Zig Cookbook Logo](/images/logo.webp) + +[Zig cookbook](https://github.com/zigcc/zig-cookbook) is a collection of simple Zig programs that demonstrate good practices to accomplish common programming tasks. + +> - Main branch tracks Zig 0.14.0 and master, and are tested on Linux and macOS via GitHub actions. +> - Earlier Zig support could be found in [other branches](https://github.com/zigcc/zig-cookbook/branches). + +# How to use + +[The website](https://cookbook.ziglang.cc/) is generated by [zine-ssg](https://zine-ssg.io), a static site generator for Zig.`zine` will start a server at `http://localhost:1990` for preview. + +Each recipe is accompanied by an illustrative example named after its corresponding sequence number. These examples can be executed using the command `zig build run-{chapter-num}-{sequence-num}`, or `zig build run-all` to execute all. + +> ## Note +> Some recipes may depend on system libraries +> - Use `make install-deps` to install client libraries, and +> - `docker-compose up -d` to start required databases. + +# Contributing + +This cookbook is a work in progress, and we welcome contributions from the community. If you have a favorite recipe that you'd like to share, please submit a [pull request](https://github.com/zigcc/zig-cookbook/pulls). + +# Acknowledgment + +The **initial** version of the Zig Cookbook was inspired by several other similar projects. We would like to thank the following projects, thanks for their awesome work. + +- [Rust Cookbook](https://github.com/rust-lang-nursery/rust-cookbook) + +The **current** version of the Zig Cookbook is based on [zine-ssg](https://zine-ssg.io), thanks for their awesome work. + +# Star History + +```=html + + Star History + +``` + +# License + +The markdown files are licensed under [CC BY-NC-ND 4.0 DEED](https://creativecommons.org/licenses/by-nc-nd/4.0/), and zig files are under MIT. diff --git a/src/toc.smd b/src/toc.smd new file mode 100644 index 0000000..34edadb --- /dev/null +++ b/src/toc.smd @@ -0,0 +1,90 @@ +--- +.title = "introduction", +.date = "2024-01-01", +.author = "ZigCC", +.layout = "section.shtml", +--- + +# Summary + +[Introduction](/) + +- File System + + - [Read file line by line](01-01-read-file-line-by-line) + - [Mmap file](01-02-mmap-file) + - [Find Files modified in the last 24 hours](01-03-file-modified-24h-ago) + - [Check file existence](01-04-file-exists) + - [Iterate directory](01-05-iterate-dir) + +- Cryptography + + - [Calculate SHA-256 digest of a file](02-01-sha-digest) + - [Salt and hash a password with PBKDF2](02-02-pbkdf2) + +- Date and Time + + - [Measure the elapsed time between two code sections](03-01-elapsed-time) + +- Network + + - [Listen on unused port TCP/IP](04-01-tcp-server) + - [TCP Client](04-02-tcp-client) + - [UDP Echo](04-03-udp-echo) + +- Web Programming + + - [HTTP Get](05-01-http-get) + - [HTTP Post](05-02-http-post) + - [HTTP Server(std)](05-03-http-server-std) + +- Algorithms + + - [Generate Random Values](06-01-rand) + +- Concurrency + + - [Explicit Threads](07-01-spawn) + - [Shared Data](07-02-shared-data) + - [Thread pool](07-03-threadpool) + - [Run Once](07-04-run-once) + +- Operating System + + - [Processor](08-01-cpu-count) + - [External Command](08-02-external) + +- Development Tools + + - [Versioning](09-01-semver) + +- Encoding + + - [(De)serialize JSON](10-01-json) + - [(De)serialize Zon](10-02-zon) + - [Encode and decode base64](10-03-base64) + +- Mathematics + + - [Complex Numbers](11-01-complex-numbers) + +- Data Structures + + - [Bitfield](12-01-bitfield) + - [Singly Linked List](12-02-singly-linked-list) + - [Doubly Linked List](12-03-doubly-linked-list) + +- Command line + + - [Argument Parsing](13-01-argparse) + - ANSI Terminal + +- [Database](database) + + - [SQLite](14-01-sqlite) + - [Postgres](14-02-postgres) + - [MySQL](14-03-mysql) + +- Text Processing + - [Regex Expressions](15-01-regex) + - [String Parsing](15-02-string) diff --git a/static/last-changed.css b/static/last-changed.css deleted file mode 100644 index 7c46d76..0000000 --- a/static/last-changed.css +++ /dev/null @@ -1,6 +0,0 @@ -footer { - font-size: 0.8em; - text-align: center; - border-top: 1px solid black; - padding: 5px 0; -} diff --git a/static/zig-hl.js b/static/zig-hl.js deleted file mode 100644 index b2e8497..0000000 --- a/static/zig-hl.js +++ /dev/null @@ -1,73 +0,0 @@ -const zigLanguageSupport = (hljs) => { - return { - name: "Zig", - aliases: ["zig"], - keywords: { - keyword: - "unreachable continue errdefer suspend return resume cancel break catch async await defer asm try " + - "threadlocal linksection allowzero stdcallcc volatile comptime noalias nakedcc inline export packed extern align const pub var " + - "struct union error enum while for switch orelse else and if or usingnamespace test fn", - type: "comptime_float comptime_int c_longdouble c_ulonglong c_longlong c_voidi8 noreturn c_ushort anyerror promise c_short c_ulong c_uint c_long isize c_int usize void f128 i128 type bool u128 u16 f64 f32 u64 i16 f16 i32 u32 i64 u8 i0 u0", - literal: "undefined false true null", - }, - contains: [ - hljs.C_LINE_COMMENT_MODE, - hljs.QUOTE_STRING_MODE, - hljs.APOS_STRING_MODE, - hljs.C_NUMBER_MODE, - { - className: "string", - begin: "@[a-zA-Z_]\\w*", - }, - { - className: "meta", - begin: /@[a-zA-Z_]\w*/, - }, - { - className: "symbol", - begin: /'[a-zA-Z_][a-zA-Z0-9_]*'/, - }, - { - className: "literal", - begin: /\\[xuU][a-fA-F0-9]+/, - }, - { - className: "number", - begin: /\b0x[0-9a-fA-F]+/, - }, - { - className: "number", - begin: /\b0b[01]+/, - }, - { - className: "number", - begin: /\b0o[0-7]+/, - }, - { - className: "number", - begin: /\b[0-9]+\b/, - }, - hljs.REGEXP_MODE, - { - // multiline string literals - className: "string", - begin: /\\/, end: /$/, - relevance: 0, - contains: [ - { - begin: /\\/, end: /$/, - relevance: 0, - }, - ], - }, - ], - }; -}; - -document.addEventListener('DOMContentLoaded', (event) => { - if (typeof hljs !== 'undefined') { - console.log("register zig support"); - hljs.registerLanguage("zig", zigLanguageSupport); - hljs.initHighlighting(); - } -}); diff --git a/zine.ziggy b/zine.ziggy new file mode 100644 index 0000000..d770804 --- /dev/null +++ b/zine.ziggy @@ -0,0 +1,9 @@ +Site { + .title = "Zig cookbook", + .host_url = "https://cookbook.ziglang.cc", + .content_dir_path = "src", + .layouts_dir_path = "layouts", + .assets_dir_path = "assets", + .static_assets = [ + ], +}