{"id":13816640,"url":"https://github.com/pysan3/neorg-templates","last_synced_at":"2025-09-23T00:32:34.853Z","repository":{"id":159394494,"uuid":"628542907","full_name":"pysan3/neorg-templates","owner":"pysan3","description":"A template file mechanism for norg files","archived":false,"fork":false,"pushed_at":"2024-02-11T01:53:20.000Z","size":98,"stargazers_count":58,"open_issues_count":1,"forks_count":5,"subscribers_count":3,"default_branch":"main","last_synced_at":"2024-11-19T13:38:42.971Z","etag":null,"topics":["lua","neorg","neovim","norg","nvim","template","templates"],"latest_commit_sha":null,"homepage":"","language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/pysan3.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","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}},"created_at":"2023-04-16T09:24:53.000Z","updated_at":"2024-11-09T06:27:25.000Z","dependencies_parsed_at":"2023-11-15T09:31:25.227Z","dependency_job_id":"d77596f2-9cdf-43bd-8927-67e89677f104","html_url":"https://github.com/pysan3/neorg-templates","commit_stats":null,"previous_names":[],"tags_count":6,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pysan3%2Fneorg-templates","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pysan3%2Fneorg-templates/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pysan3%2Fneorg-templates/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pysan3%2Fneorg-templates/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/pysan3","download_url":"https://codeload.github.com/pysan3/neorg-templates/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":233907868,"owners_count":18749034,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":["lua","neorg","neovim","norg","nvim","template","templates"],"created_at":"2024-08-04T05:00:48.484Z","updated_at":"2025-09-23T00:32:34.772Z","avatar_url":"https://github.com/pysan3.png","language":null,"funding_links":[],"categories":["Others","Neorg Modules"],"sub_categories":[],"readme":"# Neorg Templates\n\n\\* **This README is generated from [./README.norg](./README.norg).**\n\n## Demo\n\n![templates-demo](https://user-images.githubusercontent.com/41065736/232847417-6f7e32b8-fdd3-4464-9d67-269bb28b363c.gif)\n\n1.  `:Neorg templates fload journal` (`fload = force load`: Overwrite\n    buffer without asking)\n\n2.  `AUTHOR, TODAY...` will be automatically filled.\n\n3.  `{TITLE_INPUT}` is an `input_node` with `{TITLE}` being the default\n    placeholder text.\n\n- Changes the title.\n\n1.  Cursor at `{WEATHER}`.\n\n- Choosing between options provided from `LuaSnip`'s `choice_node`.\n\n1.  Cursor ends up at `{CURSOR}` position.\n\n\\* `{CURSOR}` is a magic keyword, which specifies the last position of\nthe cursor. More about magic keywords in [Magic\nKeywords](#magic-keywords).\n\n\\* You can use the same keyword in multiple places to insert the same\ncontent. Not possible in bare `LuaSnip`.\n\n## Usage\n\n### Template Norg Files\n\nSo, the plugin works like this. First you create a template file with\nplaceholders for dynamic values.\n\n`~/.config/nvim/templates/norg/journal.norg`\n\n``` norg\n@document.meta\ntitle: {TITLE_INPUT}\ndescription:\nauthors: {AUTHOR}\ncategories:\ncreated: {TODAY}\nupdated: {TODAY}\nversion: 1.0.0\n@end\n\n* {TITLE_INPUT}\n  Weather: {WEATHER}\n  {{:{YESTERDAY}:}}[Yesterday] - {{:{TOMORROW}:}}[Tomorrow]\n\n** Daily Review\n   - {CURSOR}\n```\n\nWhen you load this plugin, you have the command:\n`:Neorg templates load journal`.\n\nThis overwrites the current buffer and substitutes it with the content\nthe template file. This behavior can be customized. More in\n[Subcommands](#subcommands).\n\n### Autofill with `LuaSnip`\n\nBut do you see the `{AUTHOR}` placeholder in the template file?\n\nYes, it automatically substitutes those placeholders **with the power of\n`LuaSnip`**!\n\nAnd since it is a snippet, you can also use `input_node`, `choice_node`\nand all other useful nodes inside your template file! I've also added\nsome useful snippets by default so you can use them out of the box.\n\n## Installation\n\n- [lazy.nvim](https://github.com/folke/lazy.nvim) installation\n\n``` lua\n-- neorg.lua\nlocal M = {\n  \"nvim-neorg/neorg\",\n  ft = \"norg\",\n  dependencies = {\n    { \"pysan3/neorg-templates\", dependencies = { \"L3MON4D3/LuaSnip\" } }, -- ADD THIS LINE\n  },\n}\n```\n\n## Configuration\n\n``` lua\n-- See {*** Options} for more options\nM.config = function ()\n  require(\"neorg\").setup({\n    load = {\n      [\"external.templates\"] = {\n        -- templates_dir = vim.fn.stdpath(\"config\") .. \"/templates/norg\",\n        -- default_subcommand = \"add\", -- or \"fload\", \"load\"\n        -- keywords = { -- Add your own keywords.\n        --   EXAMPLE_KEYWORD = function ()\n        --     return require(\"luasnip\").insert_node(1, \"default text blah blah\")\n        --   end,\n        -- },\n        -- snippets_overwrite = {},\n      }\n    }\n  })\nend\n```\n\n### Options\n\nFind details here:\n[`module.config.public`](./lua/neorg/modules/external/templates/module.lua:59)\n\n#### `templates_dir`\n\n- `string | string[]`\n\nPath to the directories where the template files are stored.\n\n- Default: `vim.fn.stdpath(\"config\") .. \"/templates/norg\"`\n\n  - Most likely: `~/.config/nvim/templates/norg`\n\n- Only looks for 1 depth.\n\n- You may also provide multiple paths to directories with a table.\n\n  - `templates_dir = { \"~/temp_dir1/\", \"~/temp_dir2/\" }`\n\n#### `default_subcommand`\n\n- `string`\n\nDefault action to take when only filename is provided.\n\nMore details are explained in [Subcommands](#subcommands)\n\n- Default: `add` [Subcommands](#subcommands) - [`add`](#add)\n\n#### `keywords`\n\n- `{KEY: \u003csnippet_node\u003e}` \\| `{KEY: fun(...) -\u003e \u003csnippet_node\u003e}`\n\nDefine snippets to be called in placeholders. Kyes are advised to be\n`ALL_CAPITALIZED`.\n\n- Examples are provided in\n  [./lua/neorg/modules/external/templates/default_snippets.lua](./lua/neorg/modules/external/templates/default_snippets.lua)\n\n  - Read [Builtin Snippets](#builtin-snippets) for more information.\n\n- `KEY` should be the name of the placeholder\n\n- Value should be a snippet node or a function that returns a snippet\n  node.\n\n  - For example `TITLE_INPUT` needs to run `M.file_title()` right before\n    the expansion. Therefore, it is defined with a function.\n\n- First argument of nodes (`pos`) should always be `1`.\n\n  - e.g. `i(\u003cpos\u003e, \"default text\")`,\n    `c(\u003cpos\u003e, { t(\"choice1\"), t(\"choice2\") })`\n\n  - The order of jumping is dynamically calculated after loading the\n    template, so you cannot specify with integer here.\n\n#### `snippets_overwrite`\n\n- `table\u003cstring, any\u003e`\n\nOverwrite any field of\n[./lua/neorg/modules/external/templates/default_snippets.lua](./lua/neorg/modules/external/templates/default_snippets.lua).\n\n- You might want to change `date_format`.\n\n  - For more tags, see: \u003chttps://www.lua.org/pil/22.1.html\u003e\n\n``` lua\n{\n  snippets_overwrite = {\n    date_format = [[%a, %d %b]] -- Wed, 1 Nov (norg date format)\n  }\n}\n```\n\n## Subcommands\n\nAll command in this plugin takes the format of\n`:Neorg templates \u003csubcmd\u003e \u003ctempl_name\u003e`.\n\n- `\u003csubcmd\u003e`: Sub command. Basically defines how to load the template\n  file.\n\n- `\u003ctempl_name\u003e`: Name of template file to load.\n\n  - If you want to load `\u003cconfig.templates_dir\u003e/journal.norg`, call with\n    `journal`.\n\n#### `default_subcommand` Option\n\nRead [`default_subcommand`](#defaultsubcommand) for more information. If\nyou ommit `\u003csubcmd\u003e` and call this plugin with\n`:Neorg templates \u003ctempl_name\u003e`, the behavior depends on this config\noption.\n\nYou can choose from the functions below.\n\n### `add`\n\nAdd (append) template file content to the current cursor position.\n\n### `fload`\n\nForce-load template file. Overwrites content of current file and replace\nit with LuaSnip.\n\n### `load`\n\nLoad. Similar to `fload` but asks for confirmation before deleting the\nbuffer content.\n\n## Magic Keywords\n\nMagic keywords take the format of `{CURSOR}`, same as a placeholder, but\nhas a special meaning.\n\n### `{CURSOR}`\n\nThe cursor position when the snippet ends.\n\n- Same as `i(0)`\n\n- If `{CURSOR}` is not found, the cursor will be at the end of the file.\n\n### `{METADATA}`\n\nPlaceholder for metadata. Generated by `core.norg.esupports.metagen`.\n\n- Metadata will be simply substituted with this keyword.\n\n- You cannot edit or control the output with this plugin.\n\n  - Read [Neorg - Wiki -\n    Metagen](https://github.com/nvim-neorg/neorg/wiki/Metagen) instead.\n\n- This keyword **MUST BE** at the **first line** of the template file.\n\n- In order to `:Neorg inject-metadata blog-post`, use\n  `{METADATA:blog-post}`\n\n## Tips and Tricks\n\n### Ask for a Snippet\n\nIf you are not familiar with `LuaSnip`, post what kind of snippet you\nwant! Maybe someone can help you out.\n\nPost it in the\n[Discussions](https://github.com/pysan3/neorg-templates-draft/discussions)\nwith the category \\`✂️ Ask for a Snippet \\`.\n\n### Autoload with `:Neorg journal`\n\n\u003e \u003chttps://github.com/nvim-neorg/neorg/issues/714#issuecomment-1551013595\u003e\n\n``` lua\nvim.api.nvim_create_autocmd(\"BufNewFile\", {\n  command = \"Neorg templates load journal\",\n  pattern = { neorg_dir .. \"journal/*.norg\" },\n})\n```\n\n### Builtin Snippets\n\nI will not list all builtin snippets but some useful ones that might\nneed a bit of explanation. Please read\n[`default_snippets.lua`](./lua/neorg/modules/external/templates/default_snippets.lua)\nfor the whole list.\n\n#### `TITLE`, `TITLE_INPUT`\n\nInserts the file name. `TITLE_INPUT` would be an insert node with\ndefault text being `TITLE`.\n\n#### `TODAY`, `YESTERDAY`, `TOMORROW` + `_OF_FILENAME`, `_OF_FILETREE`\n\n`TODAY_OF_FILENAME` will insert the date by parsing the filename.\n`OF_FILENAME` is useful when `journal.strategy == \"flat\"`. So, if the\nfilename is `2023-01-01.norg`, `YESTERDAY_OF_FILENAME =\u003e 2022-12-31`.\n\nSimilarly, `TODAY_OF_FILETREE` is useful when\n`journal.strategy == \"nested\"`. Ex: if the filename is\n`/path/to/2023/01/01.norg`, `YESTERDAY_OF_FILETREE =\u003e 2022-12-31`.\n\nFor more fine control, read [2. Build you own snippet\nkey.](https://github.com/pysan3/neorg-templates/discussions/15#discussioncomment-7574518)\n\n## Useful Templates\n\n- [pysan3](https://github.com/pysan3)\n\n  - [Plugin\n    Setup](https://github.com/pysan3/dotfiles/blob/main/nvim/lua/plugins/60-neorg.lua)\n\n  - [Personal\n    Keywords](https://github.com/pysan3/dotfiles/blob/main/nvim/lua/norg-config/templates.lua)\n\n  - [Templates](https://github.com/pysan3/dotfiles/tree/main/nvim/templates/norg)\n\nMore examples welcome! Create a PR to update the README.\n\n## Contribution\n\n- Please follow code style defined in [./stylua.toml](./stylua.toml)\n  using [StyLua](https://github.com/johnnymorganz/stylua).\n\n## LICENSE\n\nAll files in this repository without annotation are licensed under the\n**GPL-3.0 license** as detailed in [LICENSE](LICENSE).\n\n## FAQs\n\n### Q. Do you plan to support other snippet engines like Ultisnip?\n\nNo. This plugin heavily depends on luasnip and I do not have the time\nand interest to support other ones.\n\nThere is an [open issue](https://github.com/nvim-neorg/neorg/issues/714)\ndiscussing for a pure lua solution using autocmds.\n\nThere are other neovim template plugins (not just for norg) that do not\ndepend on luasnip. Here are some examples.\n\n- [template.nvim](https://github.com/nvimdev/template.nvim)\n\n- [skeleton.nvim](https://github.com/xvzc/skeleton.nvim)\n\n- [esqueleto.nvim](https://github.com/cvigilv/esqueleto.nvim)\n\n- [new-file-template.nvim](https://github.com/otavioschwanck/new-file-template.nvim)\n\n- [templar.nvim](https://github.com/vigoux/templar.nvim)\n\n### Q. I want to use this plugin for other filetypes!\n\nMost of the code related to luasnip and template loading mechanism is\nwritten inside\n[`snippet_handler.lua`](https://github.com/pysan3/neorg-templates/blob/main/lua/neorg/modules/external/templates/snippet_handler.lua)\nwhich **does not** rely on neorg at all. The entry point is mostly\n`load_template_at_curpos(content, fs_name)`.\n\nFor usage example, read the implementation of subcommands\n[here](https://github.com/pysan3/neorg-templates/blob/main/lua/neorg/modules/external/templates/module.lua#L78-L116).\n\nYou are free to fork / copy-paste this code as long as you respect the\n[LICENSE](#license). I just don't have the motivation to compete against\nother template plugins listed above.\n\n### Q. Where can I contact you?\n\nI'll be at [neorg's discord server](https://discord.gg/T6EgTAX7ht) with\nthe username `@pysan3`, so feel free to ping me there.\n\n### Q. Where can I donate?\n\nThank you very much but I'd be more than happy with a star for this\nrepo. Buy yourself a cup of coffee and have a nice day 😉\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpysan3%2Fneorg-templates","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpysan3%2Fneorg-templates","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpysan3%2Fneorg-templates/lists"}