1#[derive(Debug, Clone, Copy, PartialEq, Eq)]
3pub struct Template {
4 pub language: &'static str,
6 pub name: &'static str,
8 pub source: &'static str,
10}
11
12pub const TEMPLATES: &[Template] = &[
14 Template {
15 language: "python",
16 name: "http-server",
17 source: "from http.server import ThreadingHTTPServer, SimpleHTTPRequestHandler\n\nif __name__ == \"__main__\":\n server = ThreadingHTTPServer((\"127.0.0.1\", 8000), SimpleHTTPRequestHandler)\n print(\"serving on http://127.0.0.1:8000\")\n server.serve_forever()\n",
18 },
19 Template {
20 language: "python",
21 name: "argparse-cli",
22 source: "import argparse\n\nparser = argparse.ArgumentParser()\nparser.add_argument(\"name\")\nargs = parser.parse_args()\nprint(f\"hello, {args.name}\")\n",
23 },
24 Template {
25 language: "python",
26 name: "pytest-skeleton",
27 source: "def add(a, b):\n return a + b\n\n\ndef test_add():\n assert add(2, 3) == 5\n",
28 },
29 Template {
30 language: "javascript",
31 name: "fetch-json",
32 source: "const res = await fetch(process.argv[2]);\nif (!res.ok) throw new Error(`${res.status} ${res.statusText}`);\nconsole.log(JSON.stringify(await res.json(), null, 2));\n",
33 },
34 Template {
35 language: "javascript",
36 name: "express-app",
37 source: "import express from \"express\";\n\nconst app = express();\napp.get(\"/\", (_req, res) => res.send(\"hello\"));\napp.listen(3000, () => console.log(\"http://127.0.0.1:3000\"));\n",
38 },
39 Template {
40 language: "javascript",
41 name: "node-cli",
42 source: "#!/usr/bin/env node\nconst [name = \"world\"] = process.argv.slice(2);\nconsole.log(`hello, ${name}`);\n",
43 },
44 Template {
45 language: "typescript",
46 name: "fetch-json",
47 source: "const url = Deno.args[0];\nconst res = await fetch(url);\nif (!res.ok) throw new Error(`${res.status} ${res.statusText}`);\nconsole.log(JSON.stringify(await res.json(), null, 2));\n",
48 },
49 Template {
50 language: "typescript",
51 name: "express-app",
52 source: "import express from \"npm:express\";\n\nconst app = express();\napp.get(\"/\", (_req, res) => res.send(\"hello\"));\napp.listen(3000, () => console.log(\"http://127.0.0.1:3000\"));\n",
53 },
54 Template {
55 language: "typescript",
56 name: "zod-validator",
57 source: "import { z } from \"npm:zod\";\n\nconst User = z.object({ id: z.number(), name: z.string() });\nconsole.log(User.parse({ id: 1, name: \"Ada\" }));\n",
58 },
59 Template {
60 language: "rust",
61 name: "async-main",
62 source: "use anyhow::Result;\n\n#[tokio::main]\nasync fn main() -> Result<()> {\n println!(\"hello async\");\n Ok(())\n}\n",
63 },
64 Template {
65 language: "rust",
66 name: "cli-clap",
67 source: "use clap::Parser;\n\n#[derive(Parser)]\nstruct Args { name: String }\n\nfn main() {\n let args = Args::parse();\n println!(\"hello, {}\", args.name);\n}\n",
68 },
69 Template {
70 language: "rust",
71 name: "serde-roundtrip",
72 source: "use serde::{Deserialize, Serialize};\n\n#[derive(Debug, Serialize, Deserialize)]\nstruct Item { id: u64, name: String }\n\nfn main() {\n let item = Item { id: 1, name: \"demo\".into() };\n println!(\"{}\", serde_json::to_string_pretty(&item).unwrap());\n}\n",
73 },
74 Template {
75 language: "go",
76 name: "goroutine-pool",
77 source: "package main\n\nimport \"fmt\"\n\nfunc main() {\n jobs := make(chan int)\n for w := 0; w < 4; w++ {\n go func(id int) { for job := range jobs { fmt.Println(id, job) } }(w)\n }\n for i := 0; i < 10; i++ { jobs <- i }\n close(jobs)\n}\n",
78 },
79 Template {
80 language: "go",
81 name: "http-server",
82 source: "package main\n\nimport (\n \"fmt\"\n \"net/http\"\n)\n\nfunc main() {\n http.HandleFunc(\"/\", func(w http.ResponseWriter, r *http.Request) { fmt.Fprintln(w, \"hello\") })\n http.ListenAndServe(\":8080\", nil)\n}\n",
83 },
84 Template {
85 language: "go",
86 name: "errgroup",
87 source: "package main\n\nimport (\n \"context\"\n \"fmt\"\n \"golang.org/x/sync/errgroup\"\n)\n\nfunc main() {\n g, _ := errgroup.WithContext(context.Background())\n g.Go(func() error { fmt.Println(\"work\"); return nil })\n if err := g.Wait(); err != nil { panic(err) }\n}\n",
88 },
89 Template {
90 language: "c",
91 name: "linked-list",
92 source: "#include <stdio.h>\n#include <stdlib.h>\n\ntypedef struct Node { int value; struct Node *next; } Node;\n\nint main(void) {\n Node *head = malloc(sizeof(Node));\n head->value = 1; head->next = NULL;\n printf(\"%d\\n\", head->value);\n free(head);\n return 0;\n}\n",
93 },
94 Template {
95 language: "c",
96 name: "getline-loop",
97 source: "#include <stdio.h>\n#include <stdlib.h>\n\nint main(void) {\n char *line = NULL;\n size_t cap = 0;\n while (getline(&line, &cap, stdin) != -1) printf(\"%s\", line);\n free(line);\n return 0;\n}\n",
98 },
99 Template {
100 language: "c",
101 name: "pthread-counter",
102 source: "#include <pthread.h>\n#include <stdio.h>\n\nvoid *worker(void *arg) { printf(\"worker %ld\\n\", (long)arg); return NULL; }\nint main(void) { pthread_t t; pthread_create(&t, NULL, worker, (void *)1); pthread_join(t, NULL); }\n",
103 },
104 Template {
105 language: "cpp",
106 name: "vector-sort",
107 source: "#include <algorithm>\n#include <iostream>\n#include <vector>\n\nint main() {\n std::vector<int> xs{3, 1, 2};\n std::sort(xs.begin(), xs.end());\n for (int x : xs) std::cout << x << '\\n';\n}\n",
108 },
109 Template {
110 language: "cpp",
111 name: "thread-pool",
112 source: "#include <future>\n#include <iostream>\n#include <vector>\n\nint main() {\n std::vector<std::future<int>> jobs;\n for (int i = 0; i < 4; ++i) jobs.push_back(std::async([i] { return i * i; }));\n for (auto &job : jobs) std::cout << job.get() << '\\n';\n}\n",
113 },
114 Template {
115 language: "cpp",
116 name: "lambda-async",
117 source: "#include <future>\n#include <iostream>\n\nint main() {\n auto result = std::async([] { return 42; });\n std::cout << result.get() << '\\n';\n}\n",
118 },
119 Template {
120 language: "java",
121 name: "http-server",
122 source: "import com.sun.net.httpserver.HttpServer;\nimport java.net.InetSocketAddress;\n\npublic class Main {\n public static void main(String[] args) throws Exception {\n var server = HttpServer.create(new InetSocketAddress(8080), 0);\n server.createContext(\"/\", ex -> { byte[] b = \"hello\".getBytes(); ex.sendResponseHeaders(200, b.length); ex.getResponseBody().write(b); ex.close(); });\n server.start();\n }\n}\n",
123 },
124 Template {
125 language: "java",
126 name: "executor-pool",
127 source: "import java.util.concurrent.*;\n\npublic class Main {\n public static void main(String[] args) throws Exception {\n var pool = Executors.newFixedThreadPool(4);\n var f = pool.submit(() -> 42);\n System.out.println(f.get());\n pool.shutdown();\n }\n}\n",
128 },
129 Template {
130 language: "java",
131 name: "record-json",
132 source: "record User(long id, String name) {}\n\npublic class Main {\n public static void main(String[] args) {\n var user = new User(1, \"Ada\");\n System.out.println(user);\n }\n}\n",
133 },
134 Template {
135 language: "ruby",
136 name: "http-server",
137 source: "require \"webrick\"\n\nserver = WEBrick::HTTPServer.new(Port: 8000)\nserver.mount_proc(\"/\") { |_req, res| res.body = \"hello\\n\" }\ntrap(\"INT\") { server.shutdown }\nserver.start\n",
138 },
139 Template {
140 language: "ruby",
141 name: "bundler-script",
142 source: "require \"bundler/inline\"\n\ngemfile do\n source \"https://rubygems.org\"\nend\n\nputs \"ready\"\n",
143 },
144 Template {
145 language: "ruby",
146 name: "rspec-skeleton",
147 source: "def add(a, b) = a + b\n\nRSpec.describe \"add\" do\n it { expect(add(2, 3)).to eq(5) }\nend\n",
148 },
149 Template {
150 language: "bash",
151 name: "arg-parser",
152 source: "#!/usr/bin/env bash\nset -euo pipefail\n\nname=\"world\"\nwhile [[ $# -gt 0 ]]; do\n case \"$1\" in\n --name) name=\"$2\"; shift 2 ;;\n *) echo \"unknown arg: $1\" >&2; exit 2 ;;\n esac\ndone\nprintf 'hello, %s\\n' \"$name\"\n",
153 },
154 Template {
155 language: "bash",
156 name: "safe-script",
157 source: "#!/usr/bin/env bash\nset -euo pipefail\nIFS=$'\\n\\t'\n\nmain() {\n echo \"safe shell\"\n}\nmain \"$@\"\n",
158 },
159 Template {
160 language: "bash",
161 name: "parallel-xargs",
162 source: "#!/usr/bin/env bash\nset -euo pipefail\n\nprintf '%s\\n' \"$@\" | xargs -n1 -P4 -I{} sh -c 'echo processing {}'\n",
163 },
164];
165
166pub fn find(language: &str, name: &str) -> Option<&'static Template> {
168 TEMPLATES
169 .iter()
170 .find(|template| template.language == language && template.name == name)
171}
172
173pub fn names_for_language(language: &str) -> Vec<&'static str> {
175 let mut names = TEMPLATES
176 .iter()
177 .filter_map(|template| (template.language == language).then_some(template.name))
178 .collect::<Vec<_>>();
179 names.sort_unstable();
180 names
181}