{"id":51173218,"url":"https://github.com/fezcode/descry","last_synced_at":"2026-06-27T02:01:27.141Z","repository":{"id":363199125,"uuid":"1259534267","full_name":"fezcode/Descry","owner":"fezcode","description":"A keyboard-driven markdown editor in C, SDL2 \u0026 Lua — Obsidian/Lite XL ergonomics (vault, wiki links, live preview, plugin host) without the Electron tax.","archived":false,"fork":false,"pushed_at":"2026-06-26T16:42:13.000Z","size":2554,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-26T18:14:51.592Z","etag":null,"topics":["c","c11","cross-platform","knowledge-base","lua","lua-plugins","markdown","markdown-editor","md4c","native","no-electron","note-taking","notes","obsidian","pkm","sdl2","text-editor","wiki-links"],"latest_commit_sha":null,"homepage":null,"language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/fezcode.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-06-04T15:50:09.000Z","updated_at":"2026-06-26T16:42:20.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/fezcode/Descry","commit_stats":null,"previous_names":["fezcode/descry"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/fezcode/Descry","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fezcode%2FDescry","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fezcode%2FDescry/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fezcode%2FDescry/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fezcode%2FDescry/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/fezcode","download_url":"https://codeload.github.com/fezcode/Descry/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fezcode%2FDescry/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34839005,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-27T02:00:06.362Z","response_time":126,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["c","c11","cross-platform","knowledge-base","lua","lua-plugins","markdown","markdown-editor","md4c","native","no-electron","note-taking","notes","obsidian","pkm","sdl2","text-editor","wiki-links"],"created_at":"2026-06-27T02:01:26.084Z","updated_at":"2026-06-27T02:01:27.125Z","avatar_url":"https://github.com/fezcode.png","language":"C","funding_links":[],"categories":[],"sub_categories":[],"readme":"![Descry — a keyboard-driven markdown editor in C, SDL2 \u0026 Lua](./banner-image.png)\n\n# Descry\n\nA keyboard-driven markdown editor in C, SDL2, and Lua. Aims at the\nObsidian / Lite XL ergonomics — vault sidebar, wiki links, full\npreview rendering, plugin host — without the Electron tax.\n\n![Descry preview mode](./docs/screenshots/preview.png)\n\n---\n\n## What works\n\n- **Live preview** of CommonMark via [md4c](https://github.com/mity/md4c)\n  — headings, lists, task lists, code fences, block quotes, tables,\n  inline styles, links, soft and hard breaks.\n- **Edit mode** with a real text buffer (undo/redo, multi-byte caret,\n  selection, smart Enter for lists, auto-pairs, find/replace). Soft\n  word wrap on by default; toggle off (Alt+Z) for a horizontal\n  scrollbar with arrow buttons.\n- **Tabs** — several files open at once, lossless switching (each tab\n  keeps its text, cursor, scroll, and undo), reopened on next launch.\n  A toggleable **split live-preview** (Ctrl+\\\\) renders the active file\n  source-left / preview-right.\n- **Vault sidebar** with collapsible folders, drag-and-drop reorder,\n  right-click context menu, recents tracking, and **image files** that\n  open straight into the preview pane.\n- **Wiki links** `[[note name]]` resolve case-insensitively across the\n  vault; backlinks panel shows every note that points at the current\n  one.\n- **Outline panel** auto-generated from headings, pinned or modal.\n- **Find / Replace** with regex, case-insensitive, whole-word, live\n  match count, caret-aware editing, click-to-position. Searches the\n  raw source in edit mode and the rendered text in preview so the\n  highlights line up in either view.\n- **Vault-wide search** across every note with a results overlay.\n- **Quick switcher** (Ctrl+P) — recents-first, fuzzy match.\n- **Command palette** (Ctrl+Shift+P) — every action plus every\n  Lua-registered plugin action with a category chip and bound\n  shortcut.\n- **Plugin host** — drop `*.lua` in `data/plugins/`, register actions\n  with `descry.register_action(\"name\", fn)`, and do real work: read and\n  edit the open document (`descry.buffer.*`), list/open vault notes\n  (`descry.vault.list`, `descry.open`), and subscribe to `open` / `save`\n  / `text_change` events (`descry.on`). Surface output with\n  `descry.notify` / `descry.dialog`. The Plugins overlay lists every\n  loaded file and the actions each registered, with a hot-reload button.\n- **LaTeX math** — inline `$…$` and display `$$…$$` spans render\n  typographically: Greek letters, operators, `\\frac{a}{b}`, roots, and\n  simple super/subscripts become real Unicode glyphs (`$\\sum_{i=1}^{n}\n  x_i^2$` → `∑ᵢ₌₁ⁿ xᵢ²`). A typographic pass, not a full TeX engine.\n- **Graph view** (Ctrl+Shift+M) — a force-directed map of the vault's\n  wiki-link graph. Node size scales with degree, the current note is\n  highlighted; drag to pan, scroll to zoom, click a node to open it.\n- **Spell check** — opt-in (`spellcheck = true` in `settings.lua`),\n  dictionary-driven red squiggles under unknown words in the editor.\n  Points at a system word list or your own `dictionary_path`; \"Add to\n  dictionary\" remembers words in `data/.dictionary_user`.\n- **In-app modals** for Save / Save As / Rename / New File — no\n  native Win32 dialogs, full keyboard nav, sidebar-style file\n  browser.\n- **Custom title bar** with File / Edit / View / Help menus, aero\n  snap, drag-to-move, min/maximize/close, working under\n  `SDL_WINDOW_BORDERLESS` via a WS_THICKFRAME + WM_NCCALCSIZE\n  trick.\n- **Live resize indicator** — a centered `W x H` badge plus a window\n  outline render while the user drags an edge. The resize loop pumps\n  through an SDL event watch so the indicator animates during the\n  drag, not after.\n- **Plugin actions, Ctrl+click external links, image preview,\n  About dialog, settings persistence, theme picker, keybinding\n  editor, daily-notes, HTML export, ASCII-art table aligner** ...\n\n---\n\n## Screenshots\n\n### Image embeds in preview\n\n![Image rendering](docs/screenshots/images.png)\n\n### Wiki links and quote blocks\n\n![Wiki links](docs/screenshots/wiki-links.png)\n\n### Tags, lists, mid-line styling\n\n![Tags and lists](docs/screenshots/tags-and-lists.png)\n\n---\n\n## Stack\n\n| Layer            | Library                                          |\n|------------------|--------------------------------------------------|\n| Language         | C11                                              |\n| Window / input   | SDL2                                             |\n| Glyph cache      | FreeType + HarfBuzz                              |\n| Markdown parser  | [md4c](https://github.com/mity/md4c) (vendored)  |\n| Scripting        | Lua 5.4 (vendored)                               |\n| SVG icons / pills| [nanosvg](https://github.com/memononen/nanosvg) (vendored) |\n| Image decode     | libpng, libjpeg                                  |\n| Anti-aliasing    | custom analytic signed-distance-field pill rasterizer |\n| Build            | CMake + Ninja                                    |\n\nNo GTK, no Qt, no web view, no JS runtime. The compiled binary is a\nsingle `descry.exe` plus its DLL dependencies (SDL2, FreeType,\nHarfBuzz, libpng, libjpeg).\n\n---\n\n## Building\n\n### Windows (MSYS2 MinGW-w64)\n\n```sh\npacman -S mingw-w64-x86_64-{gcc,cmake,ninja,SDL2,freetype,harfbuzz,libpng,libjpeg-turbo}\ncmake -G Ninja -B build\nninja -C build\n./build/descry.exe\n```\n\n### macOS (Homebrew)\n\nApple Silicon and Intel both work; the app renders crisp on Retina and\nfalls back to system fonts (Menlo) automatically.\n\n```sh\nbrew install cmake ninja pkg-config sdl2 freetype harfbuzz libpng jpeg\n# Apple Silicon Homebrew lives under /opt/homebrew; on Intel use /usr/local.\n# libjpeg is keg-only, so point pkg-config at it explicitly:\nexport PKG_CONFIG_PATH=\"/opt/homebrew/opt/jpeg/lib/pkgconfig:/opt/homebrew/lib/pkgconfig\"\ncmake -G Ninja -B build\nninja -C build\n./build/descry\n```\n\n**Package as a double-clickable app.** To get a self-contained `Descry.app`\n(SDL/FreeType/HarfBuzz dylibs bundled inside, HiDPI-aware, ad-hoc signed so it\nlaunches locally) instead of running the binary from a terminal:\n\n```sh\nbrew install dylibbundler      # bundles the dylibs into the app\n./package_macos.sh             # -\u003e build/Descry.app\n./package_macos.sh --dmg       # also -\u003e dist/Descry-\u003cversion\u003e.dmg (drag to /Applications)\n```\n\nFor distribution to other Macs, sign with a Developer ID\n(`--sign \"Developer ID Application: …\"`) and notarize.\n\n### Linux\n\n```sh\napt install build-essential cmake ninja-build libsdl2-dev libfreetype-dev libharfbuzz-dev libpng-dev libjpeg-dev\ncmake -G Ninja -B build\nninja -C build\n./build/descry\n```\n\nOn Windows the build pulls every transitive MinGW DLL next to the exe\nvia `file(GET_RUNTIME_DEPENDENCIES)` so the build dir is portable —\nzip it and run anywhere without an MSYS2 install. The `data/` folder\nis *not* copied; the exe loads `data/` from its own directory at\nruntime, so put your vault wherever you like and point Descry at it.\n\nThe repo ships thin wrappers around the commands above: `build.ps1`\nfor Windows (MSYS2 MinGW-w64) and `build.sh` for macOS/Linux. Both\nconfigure + build into `build/`; pass `-Run` / `--run` to launch\nafterwards.\n\n### macOS notes\n\n- **Retina / HiDPI** renders at native pixel density — glyphs are\n  rasterized at the display scale while layout stays in logical points,\n  so text is sharp rather than upscaled. Crossing between a Retina and\n  a non-Retina display re-rasterizes the fonts automatically.\n- **Fonts** default to Menlo and fall back through Apple Symbols,\n  PingFang and Apple Color Emoji for symbols / CJK / emoji. A\n  `settings.lua` copied from another OS that points at a missing font\n  is detected and swapped for the platform default instead of failing\n  to start.\n- **Reveal in Finder** uses `open -R`; external links and the log\n  folder open via `open`.\n- File dialogs use AppleScript (`osascript`); logs and settings live\n  under `~/Library/Logs/Descry/`.\n\n---\n\n## Layout\n\n```\nsrc/             - C sources (single-binary)\n  main.c         - app loop, UI, every overlay\n  buffer.c/h     - the gap-free text buffer + cursor/selection/undo\n  markdown.c/h   - md4c wrapper, line/style/wiki/link extraction\n  font.c/h       - FreeType+HarfBuzz glyph cache, fallback chain\n  icons.c/h      - nanosvg icon raster + SDF pill rasterizer\n  lua_host.c/h   - Lua state, plugin loader, action registry, buffer/\n                   vault/event bridge for plugins\n  vault.c/h      - recursive directory scan + native dialogs\n  image.c/h      - PNG/JPG decode -\u003e SDL_Texture cache\n  regex.c/h      - in-house regex engine (find/replace)\n  mermaid.c/h    - mermaid diagram parse + layout\n  graph.c/h      - force-directed wiki-link graph layout\n  spell.c/h      - hash-set spell dictionary\n  tabs.c/h       - open-file tab list + park/restore\ndata/            - default vault: sample notes, init.lua, plugins/\nvendor/          - lua 5.4, md4c, nanosvg\n```\n\n---\n\n## Plugins\n\nA plugin is any `.lua` file under `data/plugins/`. The host exposes a\ntiny global table:\n\n```lua\n-- data/plugins/hello.lua\ndescry.register_action(\"say_hello\", function()\n    descry.dialog(\"Hello\", \"Hello from the plugin system!\")\nend)\n\ndescry.notify(\"[hello plugin] loaded\")\n```\n\nAfter a reload (Ctrl+Alt+P \u003e Reload, or restart), the action shows up\nin the command palette with a `Plugin` category chip and can be\ninvoked by name or bound to a key.\n\nFull reference — every available API call, lifecycle, debugging,\nand an honest list of what's *not* exposed yet — lives in\n[docs/plugins.md](docs/plugins.md).\n\n---\n\n## Keyboard\n\nA non-exhaustive list. Every binding is editable from `Settings \u003e\nKeybindings` and persists to `settings.lua` next to the exe.\n\n| Action                | Shortcut          |\n|-----------------------|-------------------|\n| Toggle edit / preview | Ctrl+E            |\n| Save                  | Ctrl+S            |\n| Save As               | Ctrl+Shift+S      |\n| New file              | Ctrl+N            |\n| Rename                | F2                |\n| Quick switcher        | Ctrl+P            |\n| Command palette       | Ctrl+Shift+P      |\n| Plugins overlay       | Ctrl+Alt+P        |\n| Find                  | Ctrl+F            |\n| Find / Replace        | Ctrl+H            |\n| Vault search          | Ctrl+Shift+F      |\n| Outline               | Ctrl+Shift+O      |\n| Backlinks             | Ctrl+Shift+B      |\n| Tags                  | Ctrl+Shift+G      |\n| Graph view            | Ctrl+Shift+M      |\n| Daily note            | Ctrl+D            |\n| Toggle sidebar        | Ctrl+B            |\n| Toggle word wrap      | Alt+Z             |\n| Help \u0026 Keybindings    | F1                |\n| Settings              | Ctrl+, or F10     |\n\nWhen word wrap is off, long edit-mode lines extend past the viewport;\nShift+wheel pans, or use the horizontal scrollbar that appears at the\nbottom of the editor. In preview, a table wider than the pane gets its\nown horizontal scrollbar beneath it — drag the thumb, or hover the\ntable and use Shift+wheel or a horizontal swipe.\n\n---\n\n## Author\n\n[fezcode](mailto:samil.bulbul@gmail.com)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffezcode%2Fdescry","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffezcode%2Fdescry","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffezcode%2Fdescry/lists"}