{"id":50290385,"url":"https://github.com/ayosec/nvim-ceramicist","last_synced_at":"2026-05-28T05:34:23.420Z","repository":{"id":358290202,"uuid":"1237094295","full_name":"ayosec/nvim-ceramicist","owner":"ayosec","description":"Neovim plugin to run commands.","archived":false,"fork":false,"pushed_at":"2026-05-16T15:58:08.000Z","size":67,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-28T05:34:20.974Z","etag":null,"topics":["command-runner","neovim-plugin"],"latest_commit_sha":null,"homepage":"https://ayosec.github.io/nvim-ceramicist/","language":"Lua","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ayosec.png","metadata":{"files":{"readme":"README.md","changelog":null,"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,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-05-12T21:44:29.000Z","updated_at":"2026-05-16T15:58:11.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/ayosec/nvim-ceramicist","commit_stats":null,"previous_names":["ayosec/nvim-ceramicist"],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/ayosec/nvim-ceramicist","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ayosec%2Fnvim-ceramicist","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ayosec%2Fnvim-ceramicist/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ayosec%2Fnvim-ceramicist/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ayosec%2Fnvim-ceramicist/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ayosec","download_url":"https://codeload.github.com/ayosec/nvim-ceramicist/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ayosec%2Fnvim-ceramicist/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33596316,"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-05-28T02:00:06.440Z","response_time":99,"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":["command-runner","neovim-plugin"],"created_at":"2026-05-28T05:34:21.521Z","updated_at":"2026-05-28T05:34:23.413Z","avatar_url":"https://github.com/ayosec.png","language":"Lua","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003c!-- panvimdoc-ignore-start --\u003e\n\n\u003ch1 align=\"center\"\u003eCeramicist\u003c/h1\u003e\n\n\u003cdiv align=\"center\"\u003e\n\n**[Installation](#installation) | [Usage](#usage) | [Configuration](#configuration)**\n\n\u003c/div\u003e\n\n---\n\nhttps://github.com/user-attachments/assets/c420d4ed-07f9-4d69-8a27-269758f8d1c6\n\n---\n\n\u003c!-- panvimdoc-ignore-end --\u003e\n\n## Introduction\n\n\u003c!-- website-start --\u003e\n\nCeramicist is Neovim plugin to execute shell commands (like `:!`) and display\ntheir output in a dedicated window. It is similar to the [terminal] available in\nNeovim, but with some features intended to make it more convenient to use when\nyou don't need a full shell.\n\nThe main features are:\n\n* The shell command to run is written directly in Neovim's\n  [command line][h.Command-line].\n\n* Multiple commands can be appended to a single session.\n\n* The terminal window automatically starts Terminal mode when a shell command is\n  run, and returns to Normal mode when it finishes.\n\n* A header is written to show which shell command is executed.\n\n* A footer is written to show the exit status and the duration of the command.\n\n* The [statusline][h.status-line] shows information about the session.\n\n[h.Command-line]: https://neovim.io/doc/user/cmdline/\n[h.status-line]: https://neovim.io/doc/user/windows/#status-line\n[terminal]: https://neovim.io/doc/user/terminal/#terminal\n\n\u003c!-- panvimdoc-ignore-start --\u003e\n\n## Installation\n\nCeramicist can be installed with any package manager for Neovim, like\n[`vim.pack`](https://neovim.io/doc/user/pack/#_plugin-manager):\n\n```lua\nvim.pack.add { \"https://github.com/ayosec/nvim-ceramicist\" }\n\nrequire(\"ceramicist\").setup({})\n```\n\n\u003c!-- panvimdoc-ignore-end --\u003e\n\n## Usage\n\nThe `setup()` function creates an instance of Ceramicist.\n\n```lua\nrequire(\"ceramicist\").setup({})\n```\n\nThis instance is accessible through the user-command defined in the `setup()`\noptions. By default, the user-command is `:Ceramicist`:\n\n```vim\n:Ceramicist ./scripts/something\n```\n\nThe arguments of the user-command specify the shell command to run, like `:!`.\n\nIf there is another job running when a new one is executed, the previous job is\ninterrupted before starting the new one.\n\nTo define a different command name (for example, `:C`):\n\n```lua\nrequire(\"ceramicist\").setup {\n    user_command = { name = \"C\" }\n}\n```\n\nThen:\n\n```vim\n:C make test\n```\n\n### Repeating Commands\n\nIf the user-command is executed with no arguments it repeats the last shell\ncommand, like `:!!`.\n\n\n```vim\n:Ceramicist make test\n\n:Ceramicist             \" Repeat 'make test'\n```\n\nYou can also use the `rerun()` function, available in the buffer variable\n`b:ceramicist_session`, to repeat it.\n\nThe next example uses an autocommand to trigger a rerun when \u003ckbd\u003eC-R\u003c/kbd\u003e is\npressed on a window for a Ceramicist session:\n\n```lua\nvim.api.nvim_create_autocmd(\"User\", {\n    pattern = \"Ceramicist/SessionCreated\",\n    callback = function(args)\n        local map_opts = { buf = args.data.buffer }\n\n        vim.keymap.set(\n            \"n\", \"\u003cC-R\u003e\",\n            function() vim.b.ceramicist_session().rerun() end,\n            map_opts\n        )\n    end\n})\n```\n\n### Watch Mode\n\nThe `:CeramicistToggleWatch` user-command can enable or disable the Watch mode\nin a session. The user-command changes only the session in the current buffer.\nTo enable Watch mode in multiple sessions, execute it in each one.\n\nWhen Watch mode is enabled, the last shell command in the session is repeated\nafter saving changes on any buffer. See `:h BufWritePost`.\n\n### Content Reset\n\nIf the user-command is executed with the `!` modifier (see `:h :_!`)\nthe output from previous jobs is removed before running a new one:\n\n```vim\n:Ceramicist scripts/tests       \" The output is added to the session.\n\n:Ceramicist! scripts/tests      \" Reset session before running the job.\n```\n\n### Multiple Sessions\n\nMultiple sessions of the same instance can be created by adding a number\nto the user-command, either before or after the name:\n\n```vim\n:Ceramicist scripts/something       \" Default session.\n\n:2Ceramicist scripts/other          \" Session 2\n\n:Ceramicist2 scripts/other          \" Session 2\n```\n\nThe number is the session id. Its default value depends on the context where the\nuser-command is executed:\n\n- If the current buffer is a Ceramicist session, use its id.\n- If there is at least one session, use the smallest id.\n- If there are no sessions, defaults to `1`.\n\n### Multiple Instances\n\nMultiple instances of Ceramicist can be created with different calls to\n`setup()`, each one with its own user-command name.\n\nThe next example defines an instance on `:C` with the default configuration, and\nanother instance on `:M` that executes `make(1)` instead of a shell expression.\nIt also provides a custom completion list for `:M`:\n\n```lua\nrequire(\"ceramicist\").setup {\n    user_command = { name = \"C\" }\n}\n\nrequire(\"ceramicist\").setup {\n    user_command = {\n        name = \"M\",\n        complete = function()\n            return { \"all\", \"fmt\", \"test\" }\n        end,\n    },\n\n    job_command = function(cmdline)\n        return { \"make\", cmdline }\n    end,\n}\n```\n\nFor more details on the `user_command.complete` field, see\n`:h :command-complete` and `:h :command-completion-customlist`.\n\n### Window Placement\n\nBy default, the window for the session is open in a horizontal split at the\nbottom of the current tab. The modifiers `:vertical`, `:tab`, `:topleft`, etc,\ncan be used to change the placement of the new window:\n\n* `:topleft Ceramicist ...` open a horizontal split at the top.\n* `:vertical Ceramicist ...` open a vertical split to the right.\n* `:vertical topleft Ceramicist ...` open a vertical split to the left.\n* `:tab Ceramicist ...` open the session in a new tab.\n\n### Deleting Sessions\n\nA session can be deleted with `:bdelete!` (or just `:bd!`). When it is deleted,\nits state (the output from previous jobs, the last shell command, etc) is lost.\n\nIf there is a running job when the buffer is deleted, the job is interrupted.\n\nThe session will be recreated the next time the user-command is executed.\n\n### Listing Sessions\n\nThe function `list_sessions` returns an iterator to get all active sessions.\nThese objects can be used to add extra functionality to manage the sessions.\n\nFor example, to add a `:DeleteCeramicistSessions` user-command to delete all\nidle (i.e. without a running job) sessions:\n\n```lua\nvim.api.nvim_create_user_command(\n    \"DeleteCeramicistSessions\",\n    function()\n        for session in require(\"ceramicist\").list_sessions() do\n            if not session.is_running() then\n                vim.cmd.bdelete { session.buffer, bang = true }\n            end\n        end\n    end,\n    { desc = \"Delete idle Ceramicist sessions\" }\n)\n```\n\n## Configuration\n\nThe default configuration provided by Ceramicist is very basic, since it is\nexpected that users adjust it to their own preferences.\n\n\u003c!-- panvimdoc-ignore-start --\u003e\n\nSee [`config.lua`](./lua/ceramicist/config.lua) for a reference of all available\noptions.\n\nThe configuration is defined as the argument of the `setup()` function. Each\ncall to `setup()` creates a new Ceramicist instance. There is no global state,\nso each instance has its own configuration.\n\n\u003c!-- panvimdoc-ignore-end --\u003e\n\n\u003c!-- panvimdoc-include-comment\nThe default configuration can be used as a reference of all available options:\n--\u003e\n\n\u003c!-- panvimdoc-include-config --\u003e\n\n### Header and Footer\n\nThe fields `output.header` and `output.footer` can define functions that are\nused to render the header before running a job, and the footer after it is\nfinished.\n\nBoth functions must return a list of `{ text, highlight }` pairs, like the\n`virt_text` field of `:h nvim_buf_set_extmark`.\n\n`header()` receives a single argument, a string with the command line used to\nrun the job.\n\n`footer()` receives the exit code and the duration in nanoseconds. The exit code\ncan be either an integer, or a string with the name of the signal that stopped\nthe process.\n\n### Status Line\n\nThe field `statusline` defines a string to be used as the statusline of the\nsessions of the instance.\n\nThe buffer variable `b:ceramicist_statusline` is a function to provide a short\nsummary of the status of the session (the PID of the running job, if Watch mode\nis enabled, the full command line, etc).\n\nIf `statusline` is `false`, the statusline is not modified.\n\n### Autocommands\n\nExtra configuration options can be set by using autocommands:\n\n* `Ceramicist/SessionCreated`\n* `Ceramicist/JobFinished`\n* `Ceramicist/JobStarted`\n\nIn the `data` field, `SessionCreated` receives the buffer number, the window id,\nand the instance of the session.\n\nFor `JobStarted` and `JobFinished`, they also receive the command line to run\nthe job.\n\nThe next example uses `SessionCreated` to add 2 key mappings (\u003ckbd\u003eC-R\u003c/kbd\u003e to\nrepeat the last command, and \u003ckbd\u003eC-A\u003c/kbd\u003e to toggle Watch mode).\n\n```lua\nvim.api.nvim_create_autocmd(\"User\", {\n    pattern = \"Ceramicist/SessionCreated\",\n    callback = function(args)\n        local map_opts = { buf = args.data.buffer }\n\n        -- \u003cC-A\u003e toggle watch\n        vim.keymap.set(\"n\", \"\u003cC-A\u003e\", \"\u003cCmd\u003eCeramicistToggleWatch\u003cCR\u003e\", map_opts)\n\n        -- \u003cC-R\u003e rerun\n        vim.keymap.set(\n            \"n\", \"\u003cC-R\u003e\",\n            function() vim.b.ceramicist_session().rerun() end,\n            map_opts\n        )\n    end\n})\n```\n\nThe next example uses [`matchadd()`][h.matchadd()] to highlight some patterns when the\nshell command starts with `scripts/`.\n\n[h.matchadd()]: https://neovim.io/doc/user/vimfn/#matchadd()\n\n```lua\nvim.api.nvim_create_autocmd(\"User\", {\n    pattern = \"Ceramicist/JobStarted\",\n    callback = function(args)\n        local buffer = args.data.buffer\n        local window = args.data.window\n        local cmdline = args.data.cmdline\n\n        -- Use a buffer variable to track if the matchadd() is done.\n        if vim.b[buffer].has_matchadd then return end\n\n        if vim.startswith(cmdline, \"scripts/\") then\n            vim.b[buffer].has_matchadd = true\n            vim.fn.matchadd(\"DiagnosticInfo\", \"^INFO\", 0, -1, { window = window })\n            vim.fn.matchadd(\"DiagnosticError\", \"^ERROR\", 0, -1, { window = window })\n        end\n    end\n})\n```\n\n\n### Example\n\nThe configuration example below:\n\n- Creates highlight groups to replace the default colors, and add new ones for\n  the added components in the header and the footer.\n- Includes a timestamp in the header.\n- Uses custom highlights for the different components of the footer.\n- Add some key mappings to the session's buffer.\n\n\u003c!-- demo-config --\u003e\n\n```lua\nvim.api.nvim_set_hl(0, \"CeramicistNormal\", { bg = \"#001429\" })\n\nvim.api.nvim_set_hl(0, \"CeramicistHeader\", { bg = \"#002E5C\" })\nvim.api.nvim_set_hl(0, \"Ceramicist.Time\", { fg = \"#7777FF\" })\n\nvim.api.nvim_set_hl(0, \"CeramicistFooterFail\", { bg = \"#652131\" })\nvim.api.nvim_set_hl(0, \"CeramicistFooterSuccess\", { bg = \"#21653F\" })\n\nvim.api.nvim_set_hl(0, \"Ceramicist.Success.Duration\", { bg = \"#329A5F\"  })\nvim.api.nvim_set_hl(0, \"Ceramicist.Fail.Duration\", { bg = \"#9A324A\"  })\nvim.api.nvim_set_hl(0, \"Ceramicist.Fail.Code\", { bg = \"#732638\"  })\nvim.api.nvim_set_hl(0, \"Ceramicist.Fail.Signal\", { bg = \"#73264D\"  })\n\nvim.api.nvim_set_hl(0, \"CeramicistStatusLineWatch\", { bg = \"#004D4D\" })\nvim.api.nvim_set_hl(0, \"CeramicistStatusLineRunning\", { bg = \"#702000\" })\n\n\nlocal utils = require(\"ceramicist.utils\")\n\nlocal context = require(\"ceramicist\").setup({\n    user_command = { name = \"C\" },\n\n    output = {\n        gap = 3,\n\n        header = function(cmdline)\n            return {\n                { vim.fn.strftime(\" %H:%M:%S  \"), \"Ceramicist.Time\" },\n                { utils.escape_control_chars(cmdline), \"\" },\n            }\n        end,\n\n        footer = function(exit, duration)\n            local fd = \" \" .. utils.format_duration(duration) .. \" \"\n            if exit == 0 then\n                return { { \"   \", \"\" }, { fd, \"Ceramicist.Success.Duration\" } }\n            end\n\n            -- Failed\n            local status\n            if type(exit) == \"number\" then\n                status = { \" $! = \" .. exit .. \" \", \"Ceramicist.Fail.Code\" }\n            else\n                status = { \" \" .. exit .. \" \", \"Ceramicist.Fail.Signal\" }\n            end\n\n            local sep = { \"   \", \"\" }\n            return {  sep, status, sep, { fd, \"Ceramicist.Fail.Duration\" } }\n        end,\n    },\n})\n\n\nvim.api.nvim_create_autocmd(\"User\", {\n    pattern = \"Ceramicist/SessionCreated\",\n    callback = function(args)\n        local map_opts = { buf = args.data.buffer }\n\n        -- \u003cC-A\u003e toggle watch\n        vim.keymap.set(\n            \"n\", \"\u003cC-A\u003e\",\n            \"\u003cCmd\u003eCeramicistToggleWatch\u003cCR\u003e\",\n            map_opts\n        )\n\n        -- \u003cC-R\u003e rerun\n        vim.keymap.set(\n            \"n\", \"\u003cC-R\u003e\",\n            function() vim.b.ceramicist_session().rerun() end,\n            map_opts\n        )\n    end\n})\n```\n\n\u003c!-- panvimdoc-ignore-start --\u003e\n\n## Alternatives\n\nThere are many plugins providing a similar functionality to Ceramicist. This is a non-exhaustive list of alternatives:\n\n* [command-runner.nvim](https://github.com/marzeq/command-runner.nvim)\n* [como.nvim](https://github.com/JordenHuang/como.nvim)\n* [compile-mode.nvim](https://github.com/ring0-rootkit/compile-mode.nvim)\n* [erun.nvim](https://github.com/kotsmile/erun.nvim)\n* [overseer.nvim](https://github.com/stevearc/overseer.nvim)\n* [taskrun.nvim](https://github.com/yutkat/taskrun.nvim)\n\n\u003c!-- panvimdoc-ignore-end --\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fayosec%2Fnvim-ceramicist","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fayosec%2Fnvim-ceramicist","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fayosec%2Fnvim-ceramicist/lists"}