From f53890e1e1a53561e21261eceee03f87010bb3a1 Mon Sep 17 00:00:00 2001 From: dawn Date: Mon, 14 Sep 2026 09:21:20 +0300 Subject: [PATCH] web/search: add syntax highlighting to code search results Signed-off-by: dawn --- web/src/fixtures/search.ts | 2046 +++++++++++++++++ .../search/CodeResultCard.stories.svelte | 77 +- .../search/FileMatch.stories.svelte | 92 +- .../lib/components/search/FileMatch.svelte | 73 +- web/src/lib/components/search/chunks.test.ts | 85 +- web/src/lib/components/search/chunks.ts | 74 +- web/src/lib/components/search/highlight.ts | 68 + 7 files changed, 2374 insertions(+), 141 deletions(-) create mode 100644 web/src/fixtures/search.ts create mode 100644 web/src/lib/components/search/highlight.ts diff --git a/web/src/fixtures/search.ts b/web/src/fixtures/search.ts new file mode 100644 index 000000000..25ddc3c77 --- /dev/null +++ b/web/src/fixtures/search.ts @@ -0,0 +1,2046 @@ +import type { FileResult } from "$lib/api/lexicons/types/org/tangled/temp/search/searchCode"; + +export const searchResults = [ + { + branches: ["main"], + commit: "f7d662ca4fb5a5e06c850d080df3fcc29a0a5e29", + path: "meow", + ranges: [ + { + end: 4, + start: 0 + } + ], + repo: { + createdAt: "2026-07-21T08:15:24Z", + description: "test", + did: "did:plc:fzetxkvlizggfu2myme3kujc", + owner: { + did: "did:plc:dfl62fgb7wtjj3fcbb72naae", + handle: "ptr.pet" + }, + slug: "the-one-who-tests", + starCount: 0, + viewer: {} + } + }, + { + branches: ["main"], + commit: "f7b2b0ba680c6a92494c78a1c02fa28f1da321d3", + path: "oc/meow.png", + ranges: [ + { + end: 7, + start: 3 + } + ], + repo: { + createdAt: "2026-02-18T15:21:46Z", + description: '"Javeen\'s Place" Source Code', + did: "did:plc:cdaxvqjotgutzcbffc4vs7w4", + owner: { + did: "did:plc:h55zvjjs7ay2jc3nww3cakif", + handle: "tapeykatt.neocities.org", + viewer: {} + }, + slug: "tkplace", + starCount: 0, + viewer: {} + } + }, + { + branches: ["main"], + commit: "aa479faf4c0f06165cc5c08e80c65b0d4d0efa2e", + path: ".config/emacs/extras/meow.elc", + ranges: [ + { + end: 25, + start: 21 + } + ], + repo: { + createdAt: "2026-07-06T03:25:40Z", + description: "My dotFiles", + did: "did:plc:ddamtuftiet6s442eabihdp5", + owner: { + did: "did:plc:wg5ooivtpmvkslwfgfuf2ozf", + handle: "bhargavkk.tngl.sh", + viewer: {} + }, + slug: "dotfiles", + starCount: 0, + viewer: {} + } + }, + { + branches: ["master"], + commit: "67fc32665a6be3e6de95e16ad3da34a80e9fcee7", + language: "C", + path: "keyboards/meow48/meow48.c", + ranges: [ + { + end: 14, + start: 10 + }, + { + end: 21, + start: 17 + } + ], + repo: { + createdAt: "2025-10-30T09:34:41Z", + description: "keyboard stuff", + did: "did:plc:xrccdkbpx5e6d2bm6vhebt5m", + owner: { + did: "did:plc:dlxa6xglnevgshddrhscr6nj", + handle: "auri.ee", + viewer: {} + }, + slug: "qmk_firmware", + starCount: 0, + viewer: {} + } + }, + { + branches: ["main"], + commit: "1e01bcd1f7c37ee3c325ac95021ff43ddcf6d9b2", + path: "assets/slackmoji/meow-giggles.png", + ranges: [ + { + end: 21, + start: 17 + } + ], + repo: { + createdAt: "2025-09-29T00:45:03Z", + did: "did:plc:6hguzjj7i6miavpolidmirua", + owner: { + did: "did:plc:jlg3ut7bwlbmxchekufgx7d5", + handle: "ktim.tngl.sh", + viewer: {} + }, + slug: "dotfiles", + starCount: 1, + viewer: {} + } + }, + { + branches: ["main"], + commit: "192efc626ce34c3b0706f70da4ad67f421e10771", + path: "dist/_astro/meowloveme.CHDOHJSh.gif", + ranges: [ + { + end: 16, + start: 12 + } + ], + repo: { + createdAt: "2026-07-10T08:25:50+03:00", + description: "v2 of Astro Neocities Project because git is a bitch", + did: "did:plc:farnm4gstsoyw6gu6d5zkwtn", + owner: { + did: "did:plc:or2puqvwdqh7toecxthdh7ak", + handle: "thebee.bz", + viewer: {} + }, + slug: "Astro-Beebz-V2", + starCount: 0, + viewer: {} + } + }, + { + branches: ["main"], + commit: "192efc626ce34c3b0706f70da4ad67f421e10771", + path: "dist/_astro/meowthsona (1).0NPKzSQN.jpg", + ranges: [ + { + end: 16, + start: 12 + } + ], + repo: { + createdAt: "2026-07-10T08:25:50+03:00", + description: "v2 of Astro Neocities Project because git is a bitch", + did: "did:plc:farnm4gstsoyw6gu6d5zkwtn", + owner: { + did: "did:plc:or2puqvwdqh7toecxthdh7ak", + handle: "thebee.bz", + viewer: {} + }, + slug: "Astro-Beebz-V2", + starCount: 0, + viewer: {} + } + }, + { + branches: ["main"], + commit: "192efc626ce34c3b0706f70da4ad67f421e10771", + path: "src/content/galleries/blinkies/meowloveme.gif", + ranges: [ + { + end: 35, + start: 31 + } + ], + repo: { + createdAt: "2026-07-10T08:25:50+03:00", + description: "v2 of Astro Neocities Project because git is a bitch", + did: "did:plc:farnm4gstsoyw6gu6d5zkwtn", + owner: { + did: "did:plc:or2puqvwdqh7toecxthdh7ak", + handle: "thebee.bz", + viewer: {} + }, + slug: "Astro-Beebz-V2", + starCount: 0, + viewer: {} + } + }, + { + branches: ["trunk"], + commit: "7d9506616d6d702e23a29e219c436eff75767e1f", + path: "public/assets/img/buttons/meowscapebutton.png", + ranges: [ + { + end: 30, + start: 26 + } + ], + repo: { + createdAt: "2026-08-17T15:30:56Z", + description: "The Laurel system's site.", + did: "did:plc:sod3pauzdkh6ngjfvhjppazr", + owner: { + did: "did:plc:3a2h6y4tkr3joxwbtner5sve", + handle: "llia.cc", + viewer: {} + }, + slug: "laurel", + starCount: 0, + viewer: {} + } + }, + { + branches: ["main"], + commit: "192efc626ce34c3b0706f70da4ad67f421e10771", + path: "src/content/galleries/oc-art/Other/meowthsona (1).jpg", + ranges: [ + { + end: 39, + start: 35 + } + ], + repo: { + createdAt: "2026-07-10T08:25:50+03:00", + description: "v2 of Astro Neocities Project because git is a bitch", + did: "did:plc:farnm4gstsoyw6gu6d5zkwtn", + owner: { + did: "did:plc:or2puqvwdqh7toecxthdh7ak", + handle: "thebee.bz", + viewer: {} + }, + slug: "Astro-Beebz-V2", + starCount: 0, + viewer: {} + } + }, + { + branches: ["svelte"], + commit: "2d77e1854f2f3d2c6ffcfaca2b1305465188fb27", + path: "static/others/meowd.webp", + ranges: [ + { + end: 18, + start: 14 + } + ], + repo: { + createdAt: "2025-08-09T00:54:38Z", + description: "data endpoint for entity 90008 (aka. a website)", + did: "did:plc:wlcewg5d3qz5ufd43wqra26j", + owner: { + did: "did:plc:dfl62fgb7wtjj3fcbb72naae", + handle: "ptr.pet" + }, + slug: "endpoint", + starCount: 0, + viewer: {} + } + }, + { + branches: ["main"], + commit: "65b8172a63d103106a2d34b9448880313081da55", + path: "dist/webimgs/blinkie/meowloveme.gif", + ranges: [ + { + end: 25, + start: 21 + } + ], + repo: { + createdAt: "2026-02-27T03:36:12Z", + description: "Astro files for neocities webpage \n\nbuild preview", + did: "did:plc:d2ooceu4w2qn7k7mtpdn2jfk", + owner: { + did: "did:plc:or2puqvwdqh7toecxthdh7ak", + handle: "thebee.bz", + viewer: {} + }, + slug: "astro-beebz", + starCount: 0, + viewer: {} + } + }, + { + branches: ["main"], + commit: "65b8172a63d103106a2d34b9448880313081da55", + path: "public/webimgs/blinkie/meowloveme.gif", + ranges: [ + { + end: 27, + start: 23 + } + ], + repo: { + createdAt: "2026-02-27T03:36:12Z", + description: "Astro files for neocities webpage \n\nbuild preview", + did: "did:plc:d2ooceu4w2qn7k7mtpdn2jfk", + owner: { + did: "did:plc:or2puqvwdqh7toecxthdh7ak", + handle: "thebee.bz", + viewer: {} + }, + slug: "astro-beebz", + starCount: 0, + viewer: {} + } + }, + { + branches: ["main"], + commit: "b763bb607d4cf14f5d37efef6f890475ca2a432d", + path: "ec_assets/music/MeowersOfTen.mp3", + ranges: [ + { + end: 20, + start: 16 + } + ], + repo: { + createdAt: "2026-06-23T13:53:17+03:00", + description: "Monatomic kitty sandbox!", + did: "did:plc:xti3oulu2iuvty5aidlvzlfz", + owner: { + did: "did:plc:ap2utyabfsnt7tkdnizsvdvw", + handle: "muppie.xyz", + viewer: {} + }, + slug: "ecatto-decomp", + starCount: 0, + viewer: {} + } + }, + { + branches: ["main"], + commit: "a6887e1f3b80a40c8fde3ce513fba456ef3c2f2b", + path: "apps/web/public/assets/landing/statuspage-meow.png", + ranges: [ + { + end: 46, + start: 42 + } + ], + repo: { + createdAt: "2026-07-06T08:53:28.276Z", + description: + "[READ-ONLY] Mirror of https://github.com/openstatusHQ/openstatus. \ud83e\uded6 Status page with uptime monitoring & API monitoring as code \ud83e\uded6", + did: "did:plc:dcicgt22oqyl26hjts7dshrd", + owner: { + did: "did:plc:mv33toldb56v32agsunnt7sn", + handle: "openstatus.dev", + viewer: {} + }, + slug: "openstatus", + starCount: 10, + viewer: {} + } + }, + { + branches: ["main"], + commit: "a6887e1f3b80a40c8fde3ce513fba456ef3c2f2b", + path: "apps/web/public/assets/landing/statuspage-meow.dark.png", + ranges: [ + { + end: 46, + start: 42 + } + ], + repo: { + createdAt: "2026-07-06T08:53:28.276Z", + description: + "[READ-ONLY] Mirror of https://github.com/openstatusHQ/openstatus. \ud83e\uded6 Status page with uptime monitoring & API monitoring as code \ud83e\uded6", + did: "did:plc:dcicgt22oqyl26hjts7dshrd", + owner: { + did: "did:plc:mv33toldb56v32agsunnt7sn", + handle: "openstatus.dev", + viewer: {} + }, + slug: "openstatus", + starCount: 10, + viewer: {} + } + }, + { + branches: ["svelte"], + commit: "2d77e1854f2f3d2c6ffcfaca2b1305465188fb27", + path: "static/annoy/annoyance-meow_bg.wasm", + ranges: [ + { + end: 27, + start: 23 + } + ], + repo: { + createdAt: "2025-08-09T00:54:38Z", + description: "data endpoint for entity 90008 (aka. a website)", + did: "did:plc:wlcewg5d3qz5ufd43wqra26j", + owner: { + did: "did:plc:dfl62fgb7wtjj3fcbb72naae", + handle: "ptr.pet" + }, + slug: "endpoint", + starCount: 0, + viewer: {} + } + }, + { + branches: ["aurora"], + chunks: [ + { + content: + ' \n \n MEOW\n \n \n
\n

meow :3

\n
\n \n', + highlights: [ + { + end: 115, + start: 111 + }, + { + end: 194, + start: 190 + } + ], + lineStart: 4 + } + ], + commit: "009f28701fecbd62780e7f9706168ee24b486d68", + language: "HTML", + path: "meow/index.html", + repo: { + createdAt: "2026-01-09T11:05:47Z", + description: "My public website source code", + did: "did:plc:tkcgettpehf3ku6luyzqjoc4", + owner: { + did: "did:plc:y7g2koy4nqw7434s67fgfjca", + handle: "anas.tngl.sh", + viewer: {} + }, + slug: "website", + starCount: 0, + viewer: {} + } + }, + { + branches: ["svelte"], + chunks: [ + { + content: + "\n if (typeof module_or_path === 'undefined') {\n module_or_path = new URL('annoyance-meow_bg.wasm', import.meta.url);\n }\n const imports = __wbg_get_imports();\n", + highlights: [ + { + end: 98, + start: 94 + } + ], + lineStart: 1185 + } + ], + commit: "2d77e1854f2f3d2c6ffcfaca2b1305465188fb27", + language: "JavaScript", + path: "static/annoy/annoyance-meow.js", + repo: { + createdAt: "2025-08-09T00:54:38Z", + description: "data endpoint for entity 90008 (aka. a website)", + did: "did:plc:wlcewg5d3qz5ufd43wqra26j", + owner: { + did: "did:plc:dfl62fgb7wtjj3fcbb72naae", + handle: "ptr.pet" + }, + slug: "endpoint", + starCount: 0, + viewer: {} + } + }, + { + branches: ["main"], + chunks: [ + { + content: 'vim.g.colors_name = "meow"\nvim.o.termguicolors = true\n\n', + highlights: [ + { + end: 25, + start: 21 + } + ], + lineStart: 1 + } + ], + commit: "414dc2dcf04aa22e7fc4122189964a1fdbbef47c", + language: "Lua", + path: "common/neovim/colors/meow.lua", + repo: { + createdAt: "2026-07-11T21:10:26+03:00", + did: "did:plc:shv5z2mmwuyxd6p3x7jtghtf", + owner: { + did: "did:plc:boexphx7aijdxxciuvpkmyjh", + handle: "rini.tngl.sh", + viewer: { + followedBy: + "at://did:plc:boexphx7aijdxxciuvpkmyjh/sh.tangled.graph.follow/3mq2ceg44bp22" + } + }, + slug: "nixos-config", + starCount: 0, + viewer: {} + } + }, + { + branches: ["main"], + chunks: [ + { + content: "---\nname: Miss Molly Meow\nimages:\n- role: photo\n", + highlights: [ + { + end: 25, + start: 21 + } + ], + lineStart: 1 + }, + { + content: + " materializationPolicy: lazy\n source:\n url: https://d1s8fi0p4o2ghp.cloudfront.net/images/2025/MissMollyMeow.jpeg\nlinks:\n- url: https://www.facebook.com/share/1EN8Z6BeEG/?mibextid=wwXIfr\n platform: facebook\n- url: https://www.instagram.com/miss_molly_meow?igsh=Y2Nub3Q1d2JiNWR3&utm_source=qr\n platform: instagram\n---\n From to aerials to exotics, Miss Molly Meow graces stages far and wide with her sumptuous swirling\n Lyra Lover and Certified Rave babe she just finished yet another year air dancing at Shambhala and is stoked to be back here this fall for yet another Wicked Woods. \nThis gathering holds a special place within as it was her very first festival booking performing Lyra - opening the gateway to the big time stages that she so captivates. \n", + highlights: [ + { + end: 112, + start: 108 + }, + { + end: 260, + start: 256 + }, + { + end: 368, + start: 364 + } + ], + lineStart: 6 + } + ], + commit: "3d727761ce309070aebf685fb25355bae1462f31", + language: "Markdown", + path: "events/2025/contributors/Miss Molly Meow.md", + repo: { + createdAt: "2026-08-17T18:10:43+03:00", + description: "The OME plaintext workspace for Wicked Woods Music Festival", + did: "did:plc:szmxf7e3uyeyfrtegdzs2a5u", + owner: { + did: "did:plc:cqqtuv75m7e5s4uj6nw4czyu", + handle: "woody.fm", + viewer: {} + }, + slug: "wicked-woods-ome-stg", + starCount: 0, + viewer: {} + } + }, + { + branches: ["main"], + chunks: [ + { + content: "---\nname: Miss Molly Meow\nimages:\n- role: photo\n", + highlights: [ + { + end: 25, + start: 21 + } + ], + lineStart: 1 + }, + { + content: + " y: 1.83333333333333e-1\n---\nFrom to aerials to exotics, Miss Molly Meow graces stages far and wide with her sumptuous swirling\n\nLyra Lover and Certified Rave babe she\u2019s stoked to be back here this fall for yet another Wicked Woods.\n", + highlights: [ + { + end: 74, + start: 70 + } + ], + lineStart: 11 + } + ], + commit: "268540c216b97f2c181f2b198f60dff581456996", + language: "Markdown", + path: "events/2026/contributors/Miss Molly Meow.md", + repo: { + createdAt: "2026-07-13T22:08:24+03:00", + description: "The OME plaintext workspace for Wicked Woods Music Festival", + did: "did:plc:7kigfdsk33g7pctdgkyldhwc", + owner: { + did: "did:plc:5df2u7ief6m6tn77jznicxob", + handle: "wickedwoods.ca", + viewer: {} + }, + slug: "ome-workspace", + starCount: 0, + viewer: {} + } + }, + { + branches: ["main"], + chunks: [ + { + content: "---\nname: Miss Molly Meow\nimages:\n- role: photo\n", + highlights: [ + { + end: 25, + start: 21 + } + ], + lineStart: 1 + }, + { + content: + " materializationPolicy: lazy\n source:\n url: https://d1s8fi0p4o2ghp.cloudfront.net/images/2025/MissMollyMeow.jpeg\nlinks:\n- url: https://www.facebook.com/share/1EN8Z6BeEG/?mibextid=wwXIfr\n platform: facebook\n- url: https://www.instagram.com/miss_molly_meow?igsh=Y2Nub3Q1d2JiNWR3&utm_source=qr\n platform: instagram\n---\n From to aerials to exotics, Miss Molly Meow graces stages far and wide with her sumptuous swirling\n Lyra Lover and Certified Rave babe she just finished yet another year air dancing at Shambhala and is stoked to be back here this fall for yet another Wicked Woods. \nThis gathering holds a special place within as it was her very first festival booking performing Lyra - opening the gateway to the big time stages that she so captivates. \n", + highlights: [ + { + end: 112, + start: 108 + }, + { + end: 260, + start: 256 + }, + { + end: 368, + start: 364 + } + ], + lineStart: 6 + } + ], + commit: "268540c216b97f2c181f2b198f60dff581456996", + language: "Markdown", + path: "events/2025/contributors/Miss Molly Meow.md", + repo: { + createdAt: "2026-07-13T22:08:24+03:00", + description: "The OME plaintext workspace for Wicked Woods Music Festival", + did: "did:plc:7kigfdsk33g7pctdgkyldhwc", + owner: { + did: "did:plc:5df2u7ief6m6tn77jznicxob", + handle: "wickedwoods.ca", + viewer: {} + }, + slug: "ome-workspace", + starCount: 0, + viewer: {} + } + }, + { + branches: ["main"], + chunks: [ + { + content: + '// meowmix1 \'rithm, insert description here o algo as\u00ed\n// SPDX-License-Identifier: 0BSD\n\n// thats why u lwk shouldnt let yo feline step on the keyboard\nconst LUT = "m me mew meow mrow mrrr ow mreow rr nya prr purr rrr eow miao mraow"\n\t.split(" ")\n\t.map((s) =>\n', + highlights: [ + { + end: 7, + start: 3 + }, + { + end: 179, + start: 175 + } + ], + lineStart: 1 + }, + { + content: + '}\n\nexport default function meowmix1(input: string) {\n\tlet bits = purrmux1(input), mrrp = "";\n\n', + highlights: [ + { + end: 31, + start: 27 + } + ], + lineStart: 35 + } + ], + commit: "250d4c8b454160d4eae8671abdc70dc7500450e4", + language: "TypeScript", + path: "src/lib/meowmix1.ts", + repo: { + createdAt: "2026-08-12T20:32:38+03:00", + description: "silly personal website", + did: "did:plc:qumkofvwhdwb3hdr2qm2zd45", + owner: { + did: "did:plc:nqvhagqf7yyyjst7ui73nfv7", + handle: "nin0.dev", + viewer: {} + }, + slug: "web", + starCount: 0, + viewer: {} + } + }, + { + branches: ["main"], + chunks: [ + { + content: + "pub trait Meow {\n fn meow(&self) {}\n}\n\npub struct GlobalMeow;\n\nimpl Meow for GlobalMeow {}\n\npub(crate) struct PrivateMeow;\n\nimpl Meow for PrivateMeow {}\n", + highlights: [ + { + end: 14, + start: 10 + }, + { + end: 28, + start: 24 + }, + { + end: 63, + start: 59 + }, + { + end: 75, + start: 71 + }, + { + end: 90, + start: 86 + }, + { + end: 124, + start: 120 + }, + { + end: 136, + start: 132 + }, + { + end: 152, + start: 148 + } + ], + lineStart: 1 + } + ], + commit: "f7d782a3be46d6bb4b9792fe69a61db389ba1769", + language: "Rust", + path: "tests/ui/suggestions/auxiliary/meow.rs", + repo: { + createdAt: "2026-08-20T00:55:25Z", + description: "Mirror of the Rust compiler and toolchain", + did: "did:plc:eb6k4rxz22u3syzhmrdt5rjr", + owner: { + did: "did:plc:ivfwm232kvmyfn4xzwthpqj6", + handle: "nia.is.fckn.gay", + viewer: {} + }, + slug: "rust", + starCount: 0, + viewer: {} + } + }, + { + branches: ["main"], + chunks: [ + { + content: + 'import { nvmeMount, mount } from "~lib/service/mounts";\n\nexport const minecraftMeow = new ContainerService(\n "minecraft-meow",\n {\n image: "itzg/minecraft-server:java24-graalvm",\n // servicePort: 8804, // Plan\n // subdomain: "meowmeowmeow",\n ports: [25569, "24459/udp"],\n otherServicePorts: {\n "polymer-meow": 25500,\n "audio-meow": 8080,\n // map: 8100,\n },\n mounts: [nvmeMount("minecraft-meow", "/data"), mount("/dev/hugepages")],\n envs: {\n EULA: true,\n', + highlights: [ + { + end: 83, + start: 79 + }, + { + end: 125, + start: 121 + }, + { + end: 240, + start: 236 + }, + { + end: 244, + start: 240 + }, + { + end: 248, + start: 244 + }, + { + end: 328, + start: 324 + }, + { + end: 355, + start: 351 + }, + { + end: 429, + start: 425 + } + ], + lineStart: 3 + }, + { + content: + ' ENABLE_ROLLING_LOGS: true,\n // ENABLE_JMX: true,\n // JMX_HOST: "meow.bas.sh",\n LOG_TIMESTAMP: true,\n // "STOP_SERVER_ANNOUNCE_DELAY=10",\n DUMP_SERVER_PROPERTIES: true,\n MOTD: "\\u00a7r \\u00a7bmeow meow meow\\u00a7r\\n\\u00a7l \\u00a7c \\u2764 \\u00a7l:3",\n DIFFICULTY: "normal",\n OPS: ["basw"],\n', + highlights: [ + { + end: 84, + start: 80 + }, + { + end: 253, + start: 249 + }, + { + end: 258, + start: 254 + }, + { + end: 263, + start: 259 + } + ], + lineStart: 405 + }, + { + content: + ' MAX_BUILD_HEIGHT: 1024,\n VIEW_DISTANCE: 16,\n SERVER_NAME: "meow meow meow :3",\n PLAYER_IDLE_TIMEOUT: 0,\n SIMULATION_DISTANCE: 8,\n', + highlights: [ + { + end: 79, + start: 75 + }, + { + end: 84, + start: 80 + }, + { + end: 89, + start: 85 + } + ], + lineStart: 420 + }, + { + content: + ' BROADCAST_RCON_TO_OPS: false,\n ENABLE_WHITELIST: true,\n WHITELIST: ["basw", "PingwinWMeloniku", "MmeowChanNUwU"],\n RCON_PASSWORD: getEnv("RCON_PASSWORD"),\n },\n', + highlights: [ + { + end: 118, + start: 114 + } + ], + lineStart: 429 + }, + { + content: + ' },\n {\n // ignoreChanges: (await mcHasOnlinePlayers("minecraft-meow")) ? ["*"] : [],\n },\n);\n', + highlights: [ + { + end: 72, + start: 68 + } + ], + lineStart: 439 + } + ], + commit: "9e7465822a4095096158070f7bcb835778c10866", + language: "TypeScript", + path: "services/haring/games/minecraft/servers/meow.ts", + repo: { + createdAt: "2026-03-16T17:19:13+02:00", + description: "Pulumi code for my server setup", + did: "did:plc:qwx5uqtwe3m4dtp2spne625f", + owner: { + did: "did:plc:c52wep6lj4sfbsqiz3yvb55h", + handle: "bas.sh", + viewer: { + followedBy: + "at://did:plc:c52wep6lj4sfbsqiz3yvb55h/sh.tangled.graph.follow/3mawatggn2e22" + } + }, + slug: "pulumi", + starCount: 0, + viewer: {} + } + }, + { + branches: ["main"], + chunks: [ + { + content: + "len=4\n\nfor text in 'meow' 'rawr' 'nya' ':3'; do\n\tprintf '%s\\033[%bG' \"$text\" $((len + 2))\n\techo ':3'\n", + highlights: [ + { + end: 24, + start: 20 + } + ], + lineStart: 3 + } + ], + commit: "fa8decc989041a84f02cf2c53d5c3817f3d4f2e7", + language: "Shell", + path: "meow.sh", + repo: { + createdAt: "2026-07-15T16:47:40+03:00", + did: "did:plc:p7vhnic2enusvtmszh3rrhdu", + owner: { + did: "did:plc:khzb5upklnupwpxllpbmrv5a", + handle: "robinwobin.dev", + viewer: {} + }, + slug: "cdl", + starCount: 3, + viewer: {} + } + }, + { + branches: ["main"], + chunks: [ + { + content: + ';; file, You can obtain one at https://mozilla.org/MPL/2.0/.\n\n;; - Meow Mode -------------------------------------------------------------------------------------\n\n(defun +meow-join ()\n "Joins line with line below it."\n (interactive)\n (meow-join -1)\n (meow-kill))\n\n(defun meow-clipboard-replace ()\n "Replace current selection with yank.\n\nThis command supports `meow-selection-command-fallback\'."\n (interactive)\n (meow--with-selection-fallback\n (let ((select-enable-clipboard t))\n (when (meow--allow-modify-p)\n (when-let* ((s (string-trim-right (current-kill 0 t) "\\n")))\n (meow--delete-region (region-beginning) (region-end))\n (set-marker meow--replace-start-marker (point))\n (meow--insert s))))))\n\n(defun meow-shell-command ()\n "Run project-shell-command\' if in a project else `shell-command\'."\n (interactive)\n', + highlights: [ + { + end: 71, + start: 67 + }, + { + end: 176, + start: 172 + }, + { + end: 243, + start: 239 + }, + { + end: 260, + start: 256 + }, + { + end: 280, + start: 276 + }, + { + end: 370, + start: 366 + }, + { + end: 424, + start: 420 + }, + { + end: 504, + start: 500 + }, + { + end: 604, + start: 600 + }, + { + end: 678, + start: 674 + }, + { + end: 724, + start: 720 + }, + { + end: 753, + start: 749 + } + ], + lineStart: 5 + }, + { + content: + ' (call-interactively #\'shell-command)))\n\n(defun meow-quit-dwim ()\n "Quit current window or buffer."\n (interactive)\n (cond ((region-active-p)\n (meow--cancel-selection))\n ((one-window-p)\n (user-error "Only one window"))\n', + highlights: [ + { + end: 55, + start: 51 + }, + { + end: 161, + start: 157 + } + ], + lineStart: 33 + }, + { + content: + ' (delete-window))))\n\n(use-package meow\n :ensure t\n :config\n (defun meow-setup ()\n (meow-motion-define-key\n \'(":" . execute-extended-command)\n \'("Q" . delete-other-windows)\n \'("q" . meow-quit-dwim)\n \'("j" . meow-next)\n \'("k" . meow-prev)\n \'("[" . scroll-down-command)\n \'("]" . scroll-up-command)\n', + highlights: [ + { + end: 46, + start: 42 + }, + { + end: 82, + start: 78 + }, + { + end: 101, + start: 97 + }, + { + end: 211, + start: 207 + }, + { + end: 240, + start: 236 + }, + { + end: 264, + start: 260 + } + ], + lineStart: 46 + }, + { + content: + '\n ;; Meta actions\n (meow-normal-define-key\n \'("#" . ispell-word)\n \'("G" . meow-grab)\n \'("b" . meow-swap-grab)\n \'("B" . meow-sync-grab)\n \'("v" . meow-visit)\n \'("n" . meow-search)\n \'("!" . meow-shell-command)\n \'(":" . execute-extended-command)\n \'("0" . meow-expand-0)\n \'("9" . meow-expand-9)\n \'("8" . meow-expand-8)\n \'("7" . meow-expand-7)\n \'("6" . meow-expand-6)\n \'("5" . meow-expand-5)\n \'("4" . meow-expand-4)\n \'("3" . meow-expand-3)\n \'("2" . meow-expand-2)\n \'("1" . meow-expand-1)\n \'("q" . meow-quit-dwim)\n \'("Q" . delete-other-windows)\n \'("i" . meow-insert)\n \'("I" . meow-open-above)\n \'("o" . meow-append)\n \'("O" . meow-open-below)\n \'("(" . kmacro-start-macro-or-insert-counter)\n \'(")" . kmacro-end-or-call-macro)\n', + highlights: [ + { + end: 30, + start: 26 + }, + { + end: 92, + start: 88 + }, + { + end: 116, + start: 112 + }, + { + end: 145, + start: 141 + }, + { + end: 174, + start: 170 + }, + { + end: 199, + start: 195 + }, + { + end: 225, + start: 221 + }, + { + end: 297, + start: 293 + }, + { + end: 325, + start: 321 + }, + { + end: 353, + start: 349 + }, + { + end: 381, + start: 377 + }, + { + end: 409, + start: 405 + }, + { + end: 437, + start: 433 + }, + { + end: 465, + start: 461 + }, + { + end: 493, + start: 489 + }, + { + end: 521, + start: 517 + }, + { + end: 549, + start: 545 + }, + { + end: 577, + start: 573 + }, + { + end: 641, + start: 637 + }, + { + end: 667, + start: 663 + }, + { + end: 697, + start: 693 + }, + { + end: 723, + start: 719 + } + ], + lineStart: 63 + }, + { + content: + '\n ;; Movement\n (meow-normal-define-key\n \'("-" . meow-reverse)\n \'("%" . goto-match-paren)\n \'("h" . meow-left)\n \'("H" . meow-left-expand)\n \'("i" . meow-insert)\n \'("I" . meow-open-above)\n \'("j" . meow-next)\n \'("J" . meow-next-expand)\n \'("k" . meow-prev)\n \'("K" . meow-prev-expand)\n \'("l" . meow-right)\n \'("L" . meow-right-expand)\n \'("a" . meow-back-word)\n \'("A" . meow-back-symbol)\n \'("s" . meow-next-word)\n \'("S" . meow-next-symbol)\n \'("g" . goto-transient)\n \'("[" . backward-paragraph)\n', + highlights: [ + { + end: 26, + start: 22 + }, + { + end: 62, + start: 58 + }, + { + end: 120, + start: 116 + }, + { + end: 144, + start: 140 + }, + { + end: 175, + start: 171 + }, + { + end: 201, + start: 197 + }, + { + end: 231, + start: 227 + }, + { + end: 255, + start: 251 + }, + { + end: 286, + start: 282 + }, + { + end: 310, + start: 306 + }, + { + end: 341, + start: 337 + }, + { + end: 366, + start: 362 + }, + { + end: 398, + start: 394 + }, + { + end: 427, + start: 423 + }, + { + end: 458, + start: 454 + }, + { + end: 487, + start: 483 + } + ], + lineStart: 93 + }, + { + content: + '\n ;; Selection\n (meow-normal-define-key\n \'("f" . meow-find)\n \'("F" . (lambda ()\n (interactive)\n (let ((current-prefix-arg -1))\n (call-interactively \'meow-find))))\n \'("t" . meow-till)\n \'("T" . (lambda ()\n (interactive)\n (let ((current-prefix-arg -1))\n (call-interactively \'meow-till))))\n \'("," . meow-inner-of-thing)\n \'("." . meow-bounds-of-thing)\n \'("<" . meow-beginning-of-thing)\n \'(">" . meow-end-of-thing)\n \'("w" . meow-mark-word)\n \'("W" . meow-mark-symbol)\n \'("e" . meow-line)\n \'("Z" . meow-join))\n\n ;; Edits\n (meow-normal-define-key\n \'("z" . +meow-join))\n\n ;; Selection Verbs\n (meow-normal-define-key\n \'("x" . meow-delete)\n \'("X" . meow-backward-delete)\n \'("d" . meow-kill)\n \'("D" . meow-clipboard-kill)\n \'("y" . meow-save)\n \'("Y" . meow-clipboard-save)\n \'("p" . meow-yank)\n \'("P" . meow-clipboard-yank)\n \'("u" . meow-undo)\n \'("U" . meow-undo-in-selection)\n \'("c" . meow-change)\n \'("r" . meow-replace)\n \'("R" . meow-clipboard-replace)\n \'(";" . comment-dwim)\n \'("\\\\" . fill-paragraph)))\n\n (setq-default meow-replace-state-name-list\n \'((normal . "NOR")\n (motion . "MTN")\n', + highlights: [ + { + end: 27, + start: 23 + }, + { + end: 63, + start: 59 + }, + { + end: 211, + start: 207 + }, + { + end: 238, + start: 234 + }, + { + end: 386, + start: 382 + }, + { + end: 413, + start: 409 + }, + { + end: 447, + start: 443 + }, + { + end: 482, + start: 478 + }, + { + end: 520, + start: 516 + }, + { + end: 552, + start: 548 + }, + { + end: 581, + start: 577 + }, + { + end: 612, + start: 608 + }, + { + end: 636, + start: 632 + }, + { + end: 667, + start: 663 + }, + { + end: 704, + start: 700 + }, + { + end: 745, + start: 741 + }, + { + end: 781, + start: 777 + }, + { + end: 807, + start: 803 + }, + { + end: 842, + start: 838 + }, + { + end: 866, + start: 862 + }, + { + end: 900, + start: 896 + }, + { + end: 924, + start: 920 + }, + { + end: 958, + start: 954 + }, + { + end: 982, + start: 978 + }, + { + end: 1016, + start: 1012 + }, + { + end: 1040, + start: 1036 + }, + { + end: 1077, + start: 1073 + }, + { + end: 1103, + start: 1099 + }, + { + end: 1130, + start: 1126 + }, + { + end: 1230, + start: 1226 + } + ], + lineStart: 119 + }, + { + content: + ' (insert . "INS")\n (beacon . "BCN")))\n (meow-setup-indicator)\n (dolist\n (state\n', + highlights: [ + { + end: 79, + start: 75 + } + ], + lineStart: 167 + }, + { + content: + ' (help-mode . normal)\n (helpful-mode . normal)))\n (add-to-list \'meow-mode-state-list state))\n (defun advice-remove-meow-remap (orig-fun &rest args)\n "Advice to remove the remap entry from the keymap returned by foo."\n (let ((keymap (apply orig-fun args)))\n', + highlights: [ + { + end: 87, + start: 83 + }, + { + end: 139, + start: 135 + } + ], + lineStart: 180 + }, + { + content: + " keymap)))\n\n (advice-add #'meow--keypad-get-keymap-for-describe :around #'advice-remove-meow-remap)\n (meow-setup)\n (meow-global-mode 1)\n :custom\n (meow-cheatsheet-layout meow-cheatsheet-layout-qwerty)\n (meow-char-thing-table\n '((?r . round)\n (?s . square)\n", + highlights: [ + { + end: 39, + start: 35 + }, + { + end: 100, + start: 96 + }, + { + end: 115, + start: 111 + }, + { + end: 130, + start: 126 + }, + { + end: 163, + start: 159 + }, + { + end: 186, + start: 182 + }, + { + end: 220, + start: 216 + } + ], + lineStart: 188 + }, + { + content: + ' (?l . line)\n (?d . defun)))\n (meow-keypad-leader-dispatch "C-c")\n (meow-keypad-ctrl-meta-prefix ?y))\n\n(use-package meow-tree-sitter\n :ensure t\n :config\n (meow-tree-sitter-register-thing ?. \'("function" "class"))\n (meow-tree-sitter-register-thing ?\\; \'("comment")))\n', + highlights: [ + { + end: 44, + start: 40 + }, + { + end: 82, + start: 78 + }, + { + end: 130, + start: 126 + }, + { + end: 172, + start: 168 + }, + { + end: 233, + start: 229 + } + ], + lineStart: 202 + } + ], + commit: "aa479faf4c0f06165cc5c08e80c65b0d4d0efa2e", + language: "Emacs Lisp", + path: ".config/emacs/extras/meow.el", + repo: { + createdAt: "2026-07-06T03:25:40Z", + description: "My dotFiles", + did: "did:plc:ddamtuftiet6s442eabihdp5", + owner: { + did: "did:plc:wg5ooivtpmvkslwfgfuf2ozf", + handle: "bhargavkk.tngl.sh", + viewer: {} + }, + slug: "dotfiles", + starCount: 0, + viewer: {} + } + }, + { + branches: ["master"], + chunks: [ + { + content: + '\nrustPlatform.buildRustPackage (finalAttrs: {\n pname = "meow";\n version = "2.1.5";\n\n', + highlights: [ + { + end: 61, + start: 57 + } + ], + lineStart: 7 + }, + { + content: "\n postInstall = ''\n mv $out/bin/meow-cli $out/bin/meow\n '';\n\n", + highlights: [ + { + end: 40, + start: 36 + }, + { + end: 58, + start: 54 + } + ], + lineStart: 19 + }, + { + content: + ' meta = {\n description = "Print ASCII cats to your terminal";\n homepage = "https://github.com/PixelSergey/meow";\n license = lib.licenses.mit;\n mainProgram = "meow";\n maintainers = with lib.maintainers; [ pixelsergey ];\n };\n', + highlights: [ + { + end: 117, + start: 113 + }, + { + end: 175, + start: 171 + } + ], + lineStart: 26 + } + ], + commit: "1e5fb1e35bba13c3ea8bf56568c96ff953bbd0cd", + language: "Nix", + path: "pkgs/by-name/me/meow/package.nix", + repo: { + createdAt: "2026-06-15T01:13:09+03:00", + did: "did:plc:ts5zhqjndasud5h5etjzks62", + owner: { + did: "did:plc:e6e4lgy3nzdshjbpmjvnkbfd", + handle: "awoo.ren", + viewer: {} + }, + slug: "nixpkgs", + starCount: 0, + viewer: {} + } + }, + { + branches: ["main"], + chunks: [ + { + content: + '// meowmix1 \'rithm, insert description here o algo as\u00ed\n// SPDX-License-Identifier: 0BSD\n\n// thats why u lwk shouldnt let yo feline step on the keyboard\nconst LUT = "m me mew meow mrow mrrr ow mreow rr nya prr purr rrr eow miao mraow"\n\t.split(" ")\n\t.map((s) =>\n', + highlights: [ + { + end: 7, + start: 3 + }, + { + end: 179, + start: 175 + } + ], + lineStart: 1 + }, + { + content: + '}\n\nexport default function meowmix1(input: string) {\n\tlet bits = purrmux1(input), mrrp = "";\n\n', + highlights: [ + { + end: 31, + start: 27 + } + ], + lineStart: 35 + } + ], + commit: "aed3e65c98423e205507a98c198164876fd11df3", + language: "TypeScript", + path: "src/lib/meowmix1.ts", + repo: { + createdAt: "2026-05-17T11:52:06+03:00", + description: "silly personal website", + did: "did:plc:wlxkp5gtvxsejeken45nuubj", + owner: { + did: "did:web:kyu.re", + handle: "suicide.diy", + viewer: {} + }, + slug: "web", + starCount: 2, + viewer: {} + } + }, + { + branches: ["main"], + chunks: [ + { + content: + "from discord import Cog, Bot, Message\n\nfrom utils.meow_back import meow_back_for_message\n\n\nclass MeowBack(Cog):\n def __init__(self, bot: Bot):\n super().__init__()\n", + highlights: [ + { + end: 54, + start: 50 + }, + { + end: 71, + start: 67 + }, + { + end: 101, + start: 97 + } + ], + lineStart: 1 + }, + { + content: + " return\n\n meows = meow_back_for_message(message)\n\n if len(meows.strip()) > 0:\n await message.channel.send(meows)\n\n\ndef setup(bot: Bot):\n bot.add_cog(MeowBack(bot))\n", + highlights: [ + { + end: 32, + start: 28 + }, + { + end: 40, + start: 36 + }, + { + end: 87, + start: 83 + }, + { + end: 146, + start: 142 + }, + { + end: 192, + start: 188 + } + ], + lineStart: 15 + } + ], + commit: "e556cd00c0ef420a670fa485c6ed11efd1ea4f01", + language: "Python", + path: "cogs/meow_back.py", + repo: { + createdAt: "2026-06-28T11:37:28Z", + description: " A free and open source Discord bot with a lot of features. ", + did: "did:plc:qghzbihsaxhctvmz5tsmuaf7", + owner: { + did: "did:plc:vu5manrs7ipfbfk2fyn34hl3", + handle: "mldkyt.com", + viewer: {} + }, + slug: "akabot", + starCount: 0, + viewer: {} + } + }, + { + branches: ["main"], + chunks: [ + { + content: + 'from utils.server_settings import ServerSetting, SettingType\n\nmeowing = ServerSetting(\n name="Meow back at messages",\n setting_type=SettingType.NORMAL,\n default="false",\n', + highlights: [ + { + end: 66, + start: 62 + }, + { + end: 101, + start: 97 + } + ], + lineStart: 7 + }, + { + content: + '\n\ndef generate_meow():\n meow = random.choice(["meow", "nya", "mraow", "mwrmmwra"])\n\n if meow == "nya":\n return "ny" + random.randint(1, 8) * "a"\n elif meow == "mwrmmwra":\n meow = "mr"\n for i in range(random.randint(4, 12)):\n meow += random.choice(["a", "w", "r"])\n\n return meow\n\n return meow\n\n\ndef handle_meow(message: Message):\n # count meows\n count = 0\n\n', + highlights: [ + { + end: 19, + start: 15 + }, + { + end: 31, + start: 27 + }, + { + end: 54, + start: 50 + }, + { + end: 98, + start: 94 + }, + { + end: 171, + start: 167 + }, + { + end: 199, + start: 195 + }, + { + end: 270, + start: 266 + }, + { + end: 325, + start: 321 + }, + { + end: 342, + start: 338 + }, + { + end: 360, + start: 356 + }, + { + end: 396, + start: 392 + } + ], + lineStart: 56 + }, + { + content: + ' return ""\n\n return " ".join([generate_meow() for _ in range(count)]) + " :3"\n\n\n', + highlights: [ + { + end: 53, + start: 49 + } + ], + lineStart: 81 + }, + { + content: + '\n\ndef meow_back_for_message(message: Message):\n if message.guild is None:\n return ""\n', + highlights: [ + { + end: 10, + start: 6 + } + ], + lineStart: 150 + }, + { + content: + ' message_reply = " ".join(\n [\n handle_meow(message) if meowing_enabled else "",\n handle_colon_three(message) if colon_3_enabled else "",\n handle_owo(message) if owo_enabled else "",\n', + highlights: [ + { + end: 63, + start: 59 + }, + { + end: 80, + start: 76 + } + ], + lineStart: 164 + }, + { + content: + '\n with engine.begin() as c:\n meowing_enabled = meowing.get(c, message.guild.id) == "true"\n colon_3_enabled = colon_3.get(c, message.guild.id) == "true"\n owo_enabled = owo.get(c, message.guild.id) == "true"\n', + highlights: [ + { + end: 43, + start: 39 + }, + { + end: 61, + start: 57 + } + ], + lineStart: 155 + } + ], + commit: "e556cd00c0ef420a670fa485c6ed11efd1ea4f01", + language: "Python", + path: "utils/meow_back.py", + repo: { + createdAt: "2026-06-28T11:37:28Z", + description: " A free and open source Discord bot with a lot of features. ", + did: "did:plc:qghzbihsaxhctvmz5tsmuaf7", + owner: { + did: "did:plc:vu5manrs7ipfbfk2fyn34hl3", + handle: "mldkyt.com", + viewer: {} + }, + slug: "akabot", + starCount: 0, + viewer: {} + } + }, + { + branches: ["main"], + chunks: [ + { + content: + '\nfrom database import engine\nfrom utils.meow_back import meowing, wafing, barking, colon_3, owo, awawa\nfrom web.webutils.tokens import authorize, get_token_data\n\nmeow_back_bp = Blueprint("meow_back", __name__)\n\ndef handle_post(auth):\n with engine.begin() as c:\n if request.form.get("meow"):\n meowing.set(c, auth["guild"], "true")\n else:\n meowing.set(c, auth["guild"], "false")\n\n if request.form.get("waf"):\n', + highlights: [ + { + end: 44, + start: 40 + }, + { + end: 61, + start: 57 + }, + { + end: 166, + start: 162 + }, + { + end: 192, + start: 188 + }, + { + end: 297, + start: 293 + }, + { + end: 317, + start: 313 + }, + { + end: 381, + start: 377 + } + ], + lineStart: 2 + }, + { + content: + ' awawa.set(c, auth["guild"], "false")\n\n@meow_back_bp.route("/settings/meow_back", methods=["GET", "POST"])\ndef meow_back_index():\n authorization = authorize("/settings/meow_back")\n if authorization is not None:\n return authorization\n', + highlights: [ + { + end: 55, + start: 51 + }, + { + end: 85, + start: 81 + }, + { + end: 126, + start: 122 + }, + { + end: 186, + start: 182 + } + ], + lineStart: 39 + }, + { + content: + '\n with engine.begin() as c:\n meow = meowing.get(c, auth["guild"]) == "true"\n waf = wafing.get(c, auth["guild"]) == "true"\n bark = barking.get(c, auth["guild"]) == "true"\n', + highlights: [ + { + end: 43, + start: 39 + }, + { + end: 50, + start: 46 + } + ], + lineStart: 52 + }, + { + content: + ' awa = awawa.get(c, auth["guild"]) == "true"\n\n return render_template("meow_back.html",\n meow=meow, waf=waf, bark=bark, colon_3=colon_31, owo=owo1, awawa=awa)\n', + highlights: [ + { + end: 85, + start: 81 + }, + { + end: 129, + start: 125 + }, + { + end: 134, + start: 130 + } + ], + lineStart: 59 + } + ], + commit: "e556cd00c0ef420a670fa485c6ed11efd1ea4f01", + language: "Python", + path: "web/blueprints/meow_back.py", + repo: { + createdAt: "2026-06-28T11:37:28Z", + description: " A free and open source Discord bot with a lot of features. ", + did: "did:plc:qghzbihsaxhctvmz5tsmuaf7", + owner: { + did: "did:plc:vu5manrs7ipfbfk2fyn34hl3", + handle: "mldkyt.com", + viewer: {} + }, + slug: "akabot", + starCount: 0, + viewer: {} + } + }, + { + branches: ["main"], + chunks: [ + { + content: + "\n{% block main %}\n

Meow back

\n

The bot can meow back to messages. It can also bark, :3, owo, awawa and do fox noises.

\n\n{% for flash in get_flashed_messages() %}\n", + highlights: [ + { + end: 26, + start: 22 + }, + { + end: 56, + start: 52 + } + ], + lineStart: 2 + }, + { + content: + '{% endfor %}\n\n
\n \n \n
\n\n', + highlights: [ + { + end: 42, + start: 38 + }, + { + end: 101, + start: 97 + }, + { + end: 111, + start: 107 + }, + { + end: 123, + start: 119 + }, + { + end: 166, + start: 162 + }, + { + end: 172, + start: 168 + } + ], + lineStart: 11 + } + ], + commit: "e556cd00c0ef420a670fa485c6ed11efd1ea4f01", + language: "HTML", + path: "web/blueprints/templates/meow_back.html", + repo: { + createdAt: "2026-06-28T11:37:28Z", + description: " A free and open source Discord bot with a lot of features. ", + did: "did:plc:qghzbihsaxhctvmz5tsmuaf7", + owner: { + did: "did:plc:vu5manrs7ipfbfk2fyn34hl3", + handle: "mldkyt.com", + viewer: {} + }, + slug: "akabot", + starCount: 0, + viewer: {} + } + }, + { + branches: ["master"], + chunks: [ + { + content: + "String.prototype.meow = function () {\n if (!this) return 'meow';\n return `${this}, meow`;\n};\n\nconsole.log('hello'.meow());\n", + highlights: [ + { + end: 21, + start: 17 + }, + { + end: 63, + start: 59 + }, + { + end: 89, + start: 85 + }, + { + end: 120, + start: 116 + } + ], + lineStart: 1 + } + ], + commit: "e35c3ed2ab4047fdfc157f4a9cd0f0f726a522a5", + language: "JavaScript", + path: "tests/meow.js", + repo: { + createdAt: "2026-05-01T18:29:13Z", + description: "MIRROR: javascript for \ud83d\udc1c's, a tiny runtime with big ambitions", + did: "did:plc:sdvfqycbh2fcfnot362qtv27", + owner: { + did: "did:plc:ekfqkayythfa62nwye5ecvdp", + handle: "themackabu.com", + viewer: {} + }, + slug: "ant", + starCount: 1, + viewer: {} + } + }, + { + branches: ["main"], + chunks: [ + { + content: "use flake .#meow\n", + highlights: [ + { + end: 16, + start: 12 + } + ], + lineStart: 1 + } + ], + commit: "0a4f865641d65ca62ac4c0d3f2a87062bf026afa", + language: "Shell", + path: "meow/.envrc", + repo: { + createdAt: "2026-02-10T17:01:18+02:00", + description: "my nixos configuration", + did: "did:plc:npjys7exr5xycdksp3gv7hb5", + owner: { + did: "did:plc:jmnkug5wk5sjr6dhljfkjewu", + handle: "thundertheidiot.bsky.social", + viewer: {} + }, + slug: "nixdots", + starCount: 0, + viewer: {} + } + }, + { + branches: ["main"], + chunks: [ + { + content: + '}:\nstdenv.mkDerivation {\n name = "meow";\n version = "0.1";\n\n src = lib.sourceFilesBySuffices ../meow [".hs"];\n\n buildInputs = [\n', + highlights: [ + { + end: 39, + start: 35 + }, + { + end: 103, + start: 99 + } + ], + lineStart: 6 + }, + { + content: + "\n ghc $src/*.hs -outputdir ./ -hidir ./ -odir ./ -dumpdir ./ -tmpdir ./ \\\n -o $out/bin/meow\n '';\n}\n", + highlights: [ + { + end: 99, + start: 95 + } + ], + lineStart: 26 + } + ], + commit: "0a4f865641d65ca62ac4c0d3f2a87062bf026afa", + language: "Nix", + path: "pkgs/meow.nix", + repo: { + createdAt: "2026-02-10T17:01:18+02:00", + description: "my nixos configuration", + did: "did:plc:npjys7exr5xycdksp3gv7hb5", + owner: { + did: "did:plc:jmnkug5wk5sjr6dhljfkjewu", + handle: "thundertheidiot.bsky.social", + viewer: {} + }, + slug: "nixdots", + starCount: 0, + viewer: {} + } + } +] as unknown as FileResult[]; + +export const pathMatchOnlyResult = searchResults[1]; // oc/meow.png +export const highLineNumberResult = searchResults[18]; // static/annoy/annoyance-meow.js (line 1185) +export const jumpSeparatorsResult = searchResults[25]; // services/.../meow.ts (lines 3, 405, 420...) +export const manyMatchesResult = searchResults[27]; // .config/emacs/extras/meow.el (10 chunks) +export const markdownResult = searchResults[20]; // Miss Molly Meow.md diff --git a/web/src/lib/components/search/CodeResultCard.stories.svelte b/web/src/lib/components/search/CodeResultCard.stories.svelte index 7a3c3ac76..5acec9bf0 100644 --- a/web/src/lib/components/search/CodeResultCard.stories.svelte +++ b/web/src/lib/components/search/CodeResultCard.stories.svelte @@ -1,42 +1,61 @@ - + + + + + + + + + + + + {#snippet template()} +
+ {#each searchResults.slice(17, 26) as result (`${result.repo.did}/${result.commit}/${result.path}`)} + + {/each} +
+ {/snippet} +
diff --git a/web/src/lib/components/search/FileMatch.stories.svelte b/web/src/lib/components/search/FileMatch.stories.svelte index bd0bfaac4..a82cc6778 100644 --- a/web/src/lib/components/search/FileMatch.stories.svelte +++ b/web/src/lib/components/search/FileMatch.stories.svelte @@ -1,88 +1,50 @@ - + + + + + diff --git a/web/src/lib/components/search/FileMatch.svelte b/web/src/lib/components/search/FileMatch.svelte index 189d36e10..57d660cbc 100644 --- a/web/src/lib/components/search/FileMatch.svelte +++ b/web/src/lib/components/search/FileMatch.svelte @@ -7,17 +7,13 @@ Chunk, FileResult } from "$lib/api/lexicons/types/org/tangled/temp/search/searchCode"; - import { - LANGUAGE_COLORS, - LANGUAGE_COLOR_FALLBACK, - languageForPath - } from "$lib/components/repo/languageColors"; + import { LANGUAGE_COLORS, LANGUAGE_COLOR_FALLBACK } from "$lib/components/repo/languageColors"; import Button from "$lib/components/ui/Button.svelte"; import ColorBall from "$lib/components/ui/ColorBall.svelte"; import FileCardHeader from "$lib/components/repo/FileCardHeader.svelte"; - import { chunkLines } from "$lib/components/search/chunks"; + import { chunkLines, type ThemedToken } from "$lib/components/search/chunks"; + import { highlightChunks, resolveLanguage } from "$lib/components/search/highlight"; - // rest of the chunks go behind a "show more" disclosure const VISIBLE_CHUNKS = 3; let { result }: { result: FileResult } = $props(); @@ -27,6 +23,26 @@ let open = $state(true); let showAll = $state(false); + let tokensByChunk = $state.raw(undefined); + + $effect(() => { + tokensByChunk = undefined; + const currChunks = result.chunks ?? []; + if (currChunks.length === 0) return; + const lang = resolveLanguage(result.language, result.path); + if (!lang) return; + + let cancelled = false; + highlightChunks(currChunks, lang).then((tokens) => { + if (!cancelled && tokens) { + tokensByChunk = tokens; + } + }); + + return () => { + cancelled = true; + }; + }); const pathSpans = $derived( chunkLines({ content: result.path, lineStart: 1, highlights: result.ranges ?? [] })[0].spans @@ -42,16 +58,11 @@ const hidden = $derived(chunks.slice(VISIBLE_CHUNKS)); const hiddenMatches = $derived(hidden.reduce((n, c) => n + (c.highlights?.length ?? 0), 0)); - const languageColor = (lang?: string | null, path?: string) => { - if (lang && LANGUAGE_COLORS[lang]) return LANGUAGE_COLORS[lang]; - if (lang) { - const lower = lang.toLowerCase(); - const entry = Object.entries(LANGUAGE_COLORS).find(([k]) => k.toLowerCase() === lower); - if (entry) return entry[1]; - } - const guessed = path ? languageForPath(path) : null; - if (guessed && LANGUAGE_COLORS[guessed]) return LANGUAGE_COLORS[guessed]; - return LANGUAGE_COLOR_FALLBACK; + const languageColor = (lang: string) => { + if (LANGUAGE_COLORS[lang]) return LANGUAGE_COLORS[lang]; + const lower = lang.toLowerCase(); + const entry = Object.entries(LANGUAGE_COLORS).find(([k]) => k.toLowerCase() === lower); + return entry ? entry[1] : LANGUAGE_COLOR_FALLBACK; }; @@ -79,7 +90,7 @@ {#snippet actions()} {#if result.language} - + {result.language} {/if} @@ -89,7 +100,6 @@ size="small" icon={Eye} class="hidden md:inline-flex" - onclick={(e) => e.stopPropagation()} > View file @@ -100,19 +110,19 @@
- +
- {#each visible as chunk, i (chunk.lineStart)} + {#each visible as chunk, i (`${chunk.lineStart}-${i}`)} {#if i > 0} {@render gapRow()} {/if} - {@render chunkRows(chunk)} + {@render chunkRows(chunk, i)} {/each} {#if showAll} - {#each hidden as chunk (chunk.lineStart)} + {#each hidden as chunk, i (`${chunk.lineStart}-${i}`)} {@render gapRow()} - {@render chunkRows(chunk)} + {@render chunkRows(chunk, VISIBLE_CHUNKS + i)} {/each} {/if} @@ -147,21 +157,18 @@ {#snippet gapRow()} - - {/snippet} -{#snippet chunkRows(chunk: Chunk)} - {@const lines = chunkLines(chunk)} +{#snippet chunkRows(chunk: Chunk, chunkIndex: number)} + {@const lines = chunkLines(chunk, tokensByChunk?.[chunkIndex])} {#each lines as line (line.num)}
+ ··· ···
{span.text}{span.text} + {:else if span.color} + {span.text} {:else} {span.text} {/if} diff --git a/web/src/lib/components/search/chunks.test.ts b/web/src/lib/components/search/chunks.test.ts index 330af8db2..6aad04028 100644 --- a/web/src/lib/components/search/chunks.test.ts +++ b/web/src/lib/components/search/chunks.test.ts @@ -1,9 +1,18 @@ import { describe, expect, it } from "vitest"; -import { chunkLines, matchCount } from "$lib/components/search/chunks"; +import { + chunkLines, + matchCount, + mergeSpansWithTokens, + type Span, + type ThemedToken +} from "$lib/components/search/chunks"; /** compact view of a line: line number + its spans as "plain" / "[match]" */ -const shape = (chunk: Parameters[0]) => - chunkLines(chunk).map((l) => [l.num, l.spans.map((s) => (s.match ? `[${s.text}]` : s.text))]); +const shape = (chunk: Parameters[0], tokens?: ThemedToken[][]) => + chunkLines(chunk, tokens).map((l) => [ + l.num, + l.spans.map((s) => (s.match ? `[${s.text}]` : s.text)) + ]); describe("chunkLines", () => { it("numbers lines from lineStart and splits each into plain/matched spans", () => { @@ -55,6 +64,76 @@ describe("chunkLines", () => { }) ).toEqual([[1, ["a", "[bcdef]"]]]); }); + + it("applies syntax tokens to line spans", () => { + const content = "const x = 1;"; + const tokens: ThemedToken[][] = [ + [ + { content: "const", color: "kw" }, + { content: " ", color: "plain" }, + { content: "x", color: "ident" }, + { content: " = ", color: "punct" }, + { content: "1;", color: "num" } + ] + ]; + const lines = chunkLines( + { content, lineStart: 1, highlights: [{ start: 6, end: 7 }] }, + tokens + ); + expect(lines[0].spans).toEqual([ + { text: "const", color: "kw" }, + { text: " ", color: "plain" }, + { text: "x", match: true, color: "ident" }, + { text: " = ", color: "punct" }, + { text: "1;", color: "num" } + ]); + }); +}); + +describe("mergeSpansWithTokens", () => { + it("splits tokens across search match boundaries", () => { + const spans: Span[] = [{ text: "func " }, { text: "main", match: true }, { text: "()" }]; + const tokens: ThemedToken[] = [ + { content: "func", color: "kw" }, + { content: " ", color: "plain" }, + { content: "main", color: "func" }, + { content: "()", color: "punct" } + ]; + expect(mergeSpansWithTokens(spans, tokens)).toEqual([ + { text: "func", color: "kw" }, + { text: " ", color: "plain" }, + { text: "main", match: true, color: "func" }, + { text: "()", color: "punct" } + ]); + }); + + it("splits a single token when a match falls inside it", () => { + const spans: Span[] = [ + { text: 'println("hello ' }, + { text: "world", match: true }, + { text: '")' } + ]; + const tokens: ThemedToken[] = [ + { content: "println", color: "func" }, + { content: "(", color: "punct" }, + { content: '"hello world"', color: "str" }, + { content: ")", color: "punct" } + ]; + expect(mergeSpansWithTokens(spans, tokens)).toEqual([ + { text: "println", color: "func" }, + { text: "(", color: "punct" }, + { text: '"hello ', color: "str" }, + { text: "world", match: true, color: "str" }, + { text: '"', color: "str" }, + { text: ")", color: "punct" } + ]); + }); + + it("returns original spans if tokens are missing or empty", () => { + const spans: Span[] = [{ text: "hello", match: true }]; + expect(mergeSpansWithTokens(spans, undefined)).toBe(spans); + expect(mergeSpansWithTokens(spans, [])).toBe(spans); + }); }); describe("matchCount", () => { diff --git a/web/src/lib/components/search/chunks.ts b/web/src/lib/components/search/chunks.ts index 9551f5040..7f7a30e65 100644 --- a/web/src/lib/components/search/chunks.ts +++ b/web/src/lib/components/search/chunks.ts @@ -3,20 +3,22 @@ import type { Chunk, Highlight } from "$lib/api/lexicons/types/org/tangled/temp/ export interface Span { text: string; match?: boolean; + color?: string; +} + +export interface ThemedToken { + content: string; + color?: string; } export interface Line { num: number; - /** empty for a blank line */ spans: Span[]; - /** true when any part of this line matched */ - highlight: boolean; } const encoder = new TextEncoder(); const decoder = new TextDecoder(); -/** sorts and merges overlapping or adjacent ranges */ function mergeRanges(highlights: Highlight[]): Highlight[] { const sorted = highlights.filter((h) => h.end > h.start).sort((a, b) => a.start - b.start); const out: Highlight[] = []; @@ -40,27 +42,71 @@ function lineAt( ): Line { const slice = (from: number, to: number) => decoder.decode(bytes.subarray(from, to)); const spans: Span[] = []; - let highlight = false; let pos = start; - // ranges are sorted, so walking them once keeps `pos` monotonic for (const r of ranges) { const s = Math.max(r.start, start); const e = Math.min(r.end, end); if (s >= e) continue; - highlight = true; if (s > pos) spans.push({ text: slice(pos, s) }); spans.push({ text: slice(s, e), match: true }); pos = e; } if (pos < end) spans.push({ text: slice(pos, end) }); - return { num, spans, highlight }; + return { num, spans }; +} + +export function mergeSpansWithTokens(spans: Span[], tokens?: ThemedToken[]): Span[] { + if (!tokens || tokens.length === 0) return spans; + const result: Span[] = []; + let spanIdx = 0; + let spanOffset = 0; + let tokenIdx = 0; + let tokenOffset = 0; + + while (spanIdx < spans.length && tokenIdx < tokens.length) { + const span = spans[spanIdx]; + const token = tokens[tokenIdx]; + const spanRemaining = span.text.length - spanOffset; + const tokenRemaining = token.content.length - tokenOffset; + const take = Math.min(spanRemaining, tokenRemaining); + + if (take > 0) { + const entry: Span = { text: span.text.slice(spanOffset, spanOffset + take) }; + if (span.match) entry.match = true; + if (token.color) entry.color = token.color; + result.push(entry); + spanOffset += take; + tokenOffset += take; + } + + if (spanOffset >= span.text.length) { + spanIdx++; + spanOffset = 0; + } + if (tokenOffset >= token.content.length) { + tokenIdx++; + tokenOffset = 0; + } + } + + while (spanIdx < spans.length) { + const span = spans[spanIdx]; + if (spanOffset < span.text.length) { + const entry: Span = { text: span.text.slice(spanOffset) }; + if (span.match) entry.match = true; + result.push(entry); + } + spanIdx++; + spanOffset = 0; + } + + return result; } -export function chunkLines(chunk: Chunk): Line[] { +export function chunkLines(chunk: Chunk, tokens?: ThemedToken[][]): Line[] { const ranges = mergeRanges(chunk.highlights ?? []); - // trim a single trailing newline so we don't emit a spurious empty line const bytes = encoder.encode(chunk.content.replace(/\n$/, "")); const firstNum = Math.max(1, chunk.lineStart); @@ -68,12 +114,16 @@ export function chunkLines(chunk: Chunk): Line[] { let start = 0; for (let i = 0; i <= bytes.length; i++) { if (i < bytes.length && bytes[i] !== 0x0a) continue; - lines.push(lineAt(bytes, start, i, firstNum + lines.length, ranges)); + const lineIdx = lines.length; + const line = lineAt(bytes, start, i, firstNum + lineIdx, ranges); + if (tokens && tokens[lineIdx]) { + line.spans = mergeSpansWithTokens(line.spans, tokens[lineIdx]); + } + lines.push(line); start = i + 1; } return lines; } -/** total match count across a file result's chunks, for the stats line */ export const matchCount = (chunks: Chunk[]) => chunks.reduce((n, c) => n + (c.highlights?.length ?? 0), 0); diff --git a/web/src/lib/components/search/highlight.ts b/web/src/lib/components/search/highlight.ts new file mode 100644 index 000000000..837b90a00 --- /dev/null +++ b/web/src/lib/components/search/highlight.ts @@ -0,0 +1,68 @@ +import type { Chunk } from "$lib/api/lexicons/types/org/tangled/temp/search/searchCode"; +import { languageForPath } from "$lib/components/repo/languageColors"; +import type { ThemedToken } from "$lib/components/search/chunks"; + +const resolvedCache = new Map(); +const inflightLoads = new Map>(); + +export const resolveLanguage = (lang?: string | null, path?: string): string | null => { + const candidate = lang || (path ? languageForPath(path) : null); + if (!candidate) return null; + + const key = candidate.toLowerCase(); + if (resolvedCache.has(key)) return resolvedCache.get(key)!; + + return key; +}; + +export const highlightChunks = async ( + chunks: Chunk[], + lang: string +): Promise => { + if (chunks.length === 0) return null; + try { + const { SYNTAX_THEME_NAME, getSharedHighlighter } = await import("$lib/syntax"); + const hl = await getSharedHighlighter({ themes: [SYNTAX_THEME_NAME], langs: [] }); + + let resolved = resolvedCache.get(lang); + if (resolved === undefined) { + const bundled = hl.getBundledLanguages(); + resolved = + lang in bundled + ? lang + : lang.toLowerCase() in bundled + ? lang.toLowerCase() + : (hl.resolveLangAlias(lang) ?? + hl.resolveLangAlias(lang.toLowerCase()) ?? + null); + if (resolved && !(resolved in bundled)) resolved = null; + resolvedCache.set(lang, resolved); + } + + if (!resolved) return null; + + if (!hl.getLoadedLanguages().includes(resolved)) { + let loadPromise = inflightLoads.get(resolved); + if (!loadPromise) { + loadPromise = hl.loadLanguage(resolved).finally(() => { + inflightLoads.delete(resolved!); + }); + inflightLoads.set(resolved, loadPromise); + } + await loadPromise; + } + + return chunks.map((chunk) => { + const cleaned = chunk.content.replace(/\n$/, ""); + const res = hl.codeToTokens(cleaned, { + lang: resolved!, + theme: SYNTAX_THEME_NAME, + defaultColor: false, + cssVariablePrefix: "--diffs-token-" + }); + return res.tokens as ThemedToken[][]; + }); + } catch { + return null; + } +}; -- 2.51.2