{"id":13527011,"url":"https://github.com/chrisgrieser/nvim-chainsaw","last_synced_at":"2025-04-05T14:08:10.247Z","repository":{"id":214767136,"uuid":"737311790","full_name":"chrisgrieser/nvim-chainsaw","owner":"chrisgrieser","description":"Quick and feature-rich insertion of various kinds of log statements.","archived":false,"fork":false,"pushed_at":"2025-03-25T13:02:57.000Z","size":280,"stargazers_count":112,"open_issues_count":1,"forks_count":13,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-03-29T13:10:01.342Z","etag":null,"topics":["log-statements","logging","nvim-plugin","print-statements"],"latest_commit_sha":null,"homepage":"","language":"Lua","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/chrisgrieser.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","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},"funding":{"custom":"https://www.paypal.me/ChrisGrieser","ko_fi":"pseudometa"}},"created_at":"2023-12-30T15:20:58.000Z","updated_at":"2025-03-25T13:03:00.000Z","dependencies_parsed_at":"2024-02-27T12:41:17.760Z","dependency_job_id":"d03d5a08-85bd-423f-96cc-33b54cafbe65","html_url":"https://github.com/chrisgrieser/nvim-chainsaw","commit_stats":{"total_commits":186,"total_committers":7,"mean_commits":"26.571428571428573","dds":"0.048387096774193505","last_synced_commit":"2af4925afab2591bccb4118475dabfee49744311"},"previous_names":["chrisgrieser/nvim-chainsaw"],"tags_count":0,"template":false,"template_full_name":"chrisgrieser/nvim-pseudometa-plugin-template","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chrisgrieser%2Fnvim-chainsaw","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chrisgrieser%2Fnvim-chainsaw/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chrisgrieser%2Fnvim-chainsaw/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chrisgrieser%2Fnvim-chainsaw/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/chrisgrieser","download_url":"https://codeload.github.com/chrisgrieser/nvim-chainsaw/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247345853,"owners_count":20924102,"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":["log-statements","logging","nvim-plugin","print-statements"],"created_at":"2024-08-01T06:01:39.258Z","updated_at":"2025-04-05T14:08:10.173Z","avatar_url":"https://github.com/chrisgrieser.png","language":"Lua","funding_links":["https://www.paypal.me/ChrisGrieser","https://ko-fi.com/pseudometa","https://ko-fi.com/Y8Y86SQ91'"],"categories":["Lua","Debugging"],"sub_categories":["CSV Files"],"readme":"\u003c!-- LTeX: enabled=false --\u003e\n# nvim-chainsaw 🪚\n\u003c!-- LTeX: enabled=true --\u003e\n\u003ca href=\"https://dotfyle.com/plugins/chrisgrieser/nvim-chainsaw\"\u003e\n\u003cimg alt=\"badge\" src=\"https://dotfyle.com/plugins/chrisgrieser/nvim-chainsaw/shield\"/\u003e\u003c/a\u003e\n\nQuick and feature-rich insertion of various kinds of log statements.\n\n\u003chttps://github.com/chrisgrieser/nvim-chainsaw/assets/73286100/fa55ae24-deba-4fed-84e9-554d9a695ad9\u003e\n\n## Table of Contents\n\n\u003c!-- toc --\u003e\n\n- [Features](#features)\n- [Installation](#installation)\n- [Built-in language support](#built-in-language-support)\n- [Usage](#usage)\n\t* [List of commands](#list-of-commands)\n\t* [Smart variable detection](#smart-variable-detection)\n\t* [Smart insertion location](#smart-insertion-location)\n- [Configuration](#configuration)\n\t* [Basic configuration](#basic-configuration)\n\t* [Customize log statements](#customize-log-statements)\n\t* [The global pretty-logging function `Chainsaw()`](#the-global-pretty-logging-function-chainsaw)\n\t* [Make the formatter ignore the log statements](#make-the-formatter-ignore-the-log-statements)\n\t* [Status line](#status-line)\n- [Comparison with similar plugins](#comparison-with-similar-plugins)\n- [About the developer](#about-the-developer)\n\n\u003c!-- tocstop --\u003e\n\n## Features\n- Quick insertion of log statements for the variable under the cursor\n  (normal mode) or the selection (visual mode).\n- [Smart detection of the variable under the cursor](#smart-variable-detection)\n  and the [correct insertion location of the log\n  statement](#smart-insertion-location) via Treesitter.\n- Commands for a dozen different log statement types, including assert\n  statements, stack traces, or acoustic logging. All commands are\n  dot-repeatable.\n- Built-in support for ~20 common languages, with dedicated support for\n  `nvim-lua`. Easy configuration for additional languages.\n- Helper commands to remove all log statements created by `nvim-chainsaw` or to\n  clear the console.\n- Flexible templating options for customizing log statements, including support\n  for multi-line templates.\n- Status line component to display the count of log statements in the current\n  buffer. Visual indication of log statements via line-highlights, signcolumn,\n  or scrollbar (when using\n  [satellite.nvim](https://github.com/lewis6991/satellite.nvim)).\n- Auto-install a pre-commit hook that prevents committing files with the log\n  statements created by `nvim-chainsaw` (opt-in).\n\n## Installation\n**Requirements**\n- nvim 0.10+\n- Treesitter parser for the languages you with this plugin\n\n```lua\n-- lazy.nvim\n{ \n\t\"chrisgrieser/nvim-chainsaw\", \n\tevent = \"VeryLazy\",\n\topts = {} -- required even if left empty\n},\n\n-- packer\nuse { \n\t\"chrisgrieser/nvim-chainsaw\"\n\tconfig = function () \n\t\trequire(\"chainsaw\").setup()\n\tend,\n}\n```\n\nNote that the `.setup()` call (or `lazy.nvim`'s `opts`) is required, even if\ncalled without options.\n\n## Built-in language support\n- JavaScript/TypeScript (and supersets)\n- Python\n- Lua (with special considerations for `nvim-lua`[^1])\n- bash \u0026 zsh\n- AppleScript\n- Ruby\n- Rust\n- CSS[^2] (and supersets)\n- Go[^3]\n\nNot every language supports every type of log statement. For the concrete\nstatements used, see\n[log-statements-data.lua](./lua/chainsaw/config/log-statements-data.lua).\n\n[^1]: `nvim_lua` uses log statements that inspect objects and is designed to\n\twork with various notification plugins like `nvim-notify`, `snacks.nvim`, or\n\t`noice.nvim`.\n[^2]: Uses statements such as `outline: 2px solid red !important;` that are the\n\t somewhat similar logging.\n[^3]: The packages `fmt` and `time` need to be imported manually.\n\n## Usage\n\n### List of commands\nThe plugin offers various types of log statements. Bind keymaps for the ones you\nwant to use.\n\nAll operations are dot-repeatable.\n\n```lua\n-- log the name \u0026 value of the variable under the cursor\nrequire(\"chainsaw\").variableLog()\n\n-- like variableLog, but with syntax specific to inspect an object, for example\n-- `console.log(JSON.stringify(foobar))` in javascript\nrequire(\"chainsaw\").objectLog()\n\n-- inspect the type of the variable under cursor, such as `typeof foo` in js\nrequire(\"chainsaw\").typeLog()\n\n-- assertion statement for variable under cursor\nrequire(\"chainsaw\").assertLog()\n\n-- Minimal log statement, with an emoji for differentiation. Intended for\n-- control flow inspection, that is to quickly glance whether a condition was\n-- triggered or not.\nrequire(\"chainsaw\").emojiLog()\n\n-- Sound-playing statement for audible debugging.\n-- Depending on the type of log statement, it is either a terminal bell\n-- (requiring the terminal) or a system sound.\n-- Inspired by https://news.ycombinator.com/item?id=41519046\nrequire(\"chainsaw\").sound()\n\n-- create log statement, and position the cursor to enter a message\nrequire(\"chainsaw\").messageLog()\n\n-- 1st call: start measuring the time\n-- 2nd call: log the time duration since the 1st statement\nrequire(\"chainsaw\").timeLog()\n\n-- debug statements like `debugger` in javascript or `breakpoint()` in python\nrequire(\"chainsaw\").debugLog()\n\n-- prints the stacktrace of the current call\nrequire(\"chainsaw\").stacktraceLog()\n\n-- clearing statement, such as `console.clear()`\nrequire(\"chainsaw\").clearLog()\n\n---------------------------------------------------\n\n-- remove all log statements or all log statements in visually selected region \n-- created by nvim-chainsaw \nrequire(\"chainsaw\").removeLogs()\n```\n\nThese features can also be accessed with the user command `:Chainsaw`. Each\noption corresponds to the commands above. For example, `:Chainsaw\nvariableLog` is same as `:lua require(\"chainsaw\").variableLog()`.\n\nWhen using lua functions, `variableLog`, `objectLog`, `typeLog`, and `assertLog`\ncan also be used in **visual mode** to use the visual selection instead of the\nword under the cursor. `removeLogs` can also be used in visual mode to only\nremove log statements inside the selected lines.\n\n### Smart variable detection\nWhen the variable under the cursor is an object with fields, `chainsaw` attempts\nto automatically select the correct field. (Note that this feature requires the\nTreesitter parser of the respective language.)\n\n```lua\nmyVariable.myF[i]eld = \"foobar\"\n-- prints: myVariable.myField\n\nmyVa[r]iable.myField = \"foobar\"\n-- prints: myVariable\n```\n\nFiletypes currently supporting this feature:\n- Lua (and `nvim_lua`)\n- Python\n- JavaScript (and supersets)\n\nPRs adding support for more languages are welcome. See\n[smart-var-detect.lua](./lua/chainsaw/config/smart-var-detect.lua).\n\n### Smart insertion location\n`chainsaw` by default inserts the log statement below the cursor. The insertion\nlocation is automatically adapted if doing would result in invalid code. (Note\nthat this feature requires the Treesitter parser of the respective language.)\n\n```lua\n-- [] marks the cursor position\n\n-- default case: will insert the log statement below the cursor\nlocal f[o]obar = 1\n\n-- multi-line assignments: will insert log statement below the `}` line\nlocal f[o]o = {\n\tbar = 1\n}\n\n-- returns: will insert log statement above the `return` line\nlocal function foobar()\n\treturn f[o]o\nend\n```\n\nFiletypes currently supporting this feature:\n- Lua (and `nvim_lua`)\n- JavaScript (and supersets)\n\nPRs adding support for more languages are welcome. See\n[smart-insert-location.lua](./lua/chainsaw/config/smart-insert-location.lua).\n\n## Configuration\nThe `setup()` call is required.\n\n### Basic configuration\n\n```lua\n-- default settings\nrequire(\"chainsaw\").setup {\n\t-- The marker should be a unique string, since signs and highlgiths are based\n\t-- on it and since `.removeLogs()` will remove any line with it. Thus, emojis\n\t-- or unique strings like \"[Chainsaw]\" are recommended.\n\tmarker = \"🪚\",\n\n\t-- Appearance of lines with the marker\n\tvisuals = {\n\t\ticon = \"󰹈\", -- as opposed to marker only used in nvim, thus nerdfont icons are okay\n\t\tsignHlgroup = \"DiagnosticSignInfo\",\n\t\tlineHlgroup = false,\n\t\tsignPriority = 50,\n\n\t\tnvimSatelliteIntegration = {\n\t\t\tenabled = true,\n\t\t\thlgroup = \"DiagnosticSignInfo\",\n\t\t\ticon = \"▪\",\n\t\t\tleftOfScrollbar = false,\n\t\t\tpriority = 40, -- compared to other handlers (diagnostics are 50)\n\t\t},\n\t},\n\n\t-- Auto-install a pre-commit hook that prevents commits containing the marker\n\t-- string. Will not be installed if there is already another pre-commit-hook.\n\tpreCommitHook = {\n\t\tenabled = false,\n\t\tnotifyOnInstall = true,\n\t\thookPath = \".chainsaw\", -- relative to git root\n\n\t\t-- Will insert the marker as `%s`. (Pre-commit hooks requires a shebang\n\t\t-- and exit non-zero when marker is found to block the commit.)\n\t\thookContent = [[#!/bin/sh\n\t\t\tif git grep --fixed-strings --line-number \"%s\" .; then\n\t\t\t\techo\n\t\t\t\techo \"nvim-chainsaw marker found. Aborting commit.\"\n\t\t\t\texit 1\n\t\t\tfi\n\t\t]],\n\n\t\t-- If you track your nvim-config via git, and use a custom marker, you\n\t\t-- should add it to this list, since your config will then always include\n\t\t-- a marker, thus always falsely triggering the pre-commit hook.\n\t\tnotInNvimConfigDir = true,\n\n\t\t-- List of directories where the hook should not be installed if they are\n\t\t-- the git root. Supports globs and `~`. Must *fully* match the directory.\n\t\tdontInstallInDirs = {\n\t\t\t-- \"~/special-project\"\n\t\t\t-- \"~/repos/**\",\n\t\t},\n\t},\n\n\t-- configuration for specific logtypes\n\tlogTypes = {\n\t\temojiLog = {\n\t\t\temojis = { \"🔵\", \"🟩\", \"⭐\", \"⭕\", \"💜\", \"🔲\" },\n\t\t},\n\t},\n\n\t-----------------------------------------------------------------------------\n\t-- see https://github.com/chrisgrieser/nvim-chainsaw/blob/main/lua/chainsaw/config/log-statements-data.lua\n\tlogStatements = require(\"chainsaw.config.log-statements-data\").logStatements,\n\tsupersets = require(\"chainsaw.config.log-statements-data\").supersets,\n}\n```\n\n### Customize log statements\nNew log statements can be added, and existing log statements can be modified\nunder the config `logStatements`. See\n[log-statements-data.lua](./lua/chainsaw/config/log-statements-data.lua) for\nthe built-in log statements as reference. PRs adding log statements for more\nlanguages are welcome.\n\nThere are various **placeholders** that are dynamically replaced:\n- `{{marker}}` inserts the value from `config.marker`. Each log statement should\n  have one, so that the line can be removed via `.removeLogs()`.\n- `{{var}}`: variable as described further above.\n- `{{time}}`: timestamp formatted as `HH:MM:SS` (for millisecond-precision, use\n  `.timeLog()` instead)\n- `{{filename}}`: basename of the current file\n- `{{lnum}}`: current line number\n- `.emojiLog()` only: `{{emoji}}` inserts the emoji\n- `.timeLog()` only: `{{index}}` inserts a running index. (Needed to\n  differentiate between variables when using `timeLog` multiple times).\n\n```lua\nrequire(\"chainsaw\").setup ({\n\tlogStatements = {\n\t\tvariableLog = {\n\t\t\tjavascript = 'console.log(\"{{marker}} {{var}}:\", {{var}});',\n\t\t\totherFiletype = … -- \u003c-- add the statement for your filetype here\n\t\t},\n\t\t-- the same way for the other log statement operations\n\t},\n})\n```\n\n\u003e [!NOTE]\n\u003e The strings may not include line breaks. If you want to use multi-line log\n\u003e statements, use a list of strings instead, each string representing one line.\n\n### The global pretty-logging function `Chainsaw()`\n\u003cimg alt=\"Showcase nvim-lua-debug function\" width=75% src=\"https://github.com/user-attachments/assets/39681485-f077-421f-865d-c65a7c35a3c3\"\u003e\n\nThe plugin provides a globally accessible function `Chainsaw()`, specifically\ndesigned for debugging `nvim_lua`. Given a variable, it pretty-prints the\nvariable, its name, and the location of the log statement call, all in a much\nmore concise manner.\n\n**Requirements:** A notification plugin like\n[nvim-notify](https://github.com/rcarriga/nvim-notify) or\n[snacks.nvim](http://github.com/folke/snacks.nvim). Syntax highlighting inside\nthe notification requires `snacks.nvim`.\n\n**Setup:** You can use it by setting a custom log statement like this:\n\n```lua\nrequire(\"chainsaw\").setup {\n\tlogStatements = {\n\t\tvariableLog = {\n\t\t\tnvim_lua = \"Chainsaw({{var}}) -- {{marker}}\",\n\t\t},\n\t},\n}\n```\n\n\u003e [!TIP]\n\u003e To use `Chainsaw()` during or shortly after startup, you may not lazy-load\n\u003e `nvim-chainsaw`. Using `lazy.nvim`, set `lazy = false` and if needed `priority\n\u003e = 200` to ensure the plugin loads before other start-plugins.\n\nThe `lua_ls` diagnostic `undefined-global` for `Chainsaw` can be disabled with\none of the following methods:\n\n\u003cdetails\u003e\n\u003csummary\u003eOptions\u003c/summary\u003e\n\n```lua\n-- Option 1: nvim-lspconfig\nrequire(\"lspconfig\").lua_ls.setup {\n\tsettings = {\n\t\tLua = {\n\t\t\tdiagnostics = {\n\t\t\t\tglobals = { \"Chainsaw\", \"vim\" },\n\t\t\t},\n\t\t},\n\t},\n}\n```\n\n```jsonc\n// Option 2: .luarc.json\n{\n\t\"diagnostics\": {\n\t\t\"globals\": [\"Chainsaw\", \"vim\"],\n\t},\n}\n```\n\n```lua\n-- Option 3: lazydev.nvim\nopts = {\n\tlibrary = {\n\t\t{ path = \"nvim-chainsaw\", words = { \"Chainsaw\" } },\n\t},\n},\n```\n\n\u003c/details\u003e\n\n### Make the formatter ignore the log statements\nA common problem is that formatters like `prettier` split up the log statements\ninto multiple lines, making them hard to read and breaking `.removeLogs()`, which\nrelies on each line containing the marker emoji.\n\nThe simplest method to deal with this is to customize the log statement in your\nconfiguration to include an ignore-comment: `/* prettier-ignore */`\n- The log statements do not accept lines, but you can use a list of strings,\n  where each element is one line.\n- Add the marker to the added line as well, so it is included in the removal by\n  `.removeLogs()`.\n\n```lua\nrequire(\"chainsaw\").setup {\n\tlogStatements = {\n\t\tvariableLog = {\n\t\t\tjavascript = {\n\t\t\t\t\"/* prettier-ignore */ // {{marker}}\",\n\t\t\t\t'console.log(\"{{marker}} {{var}}:\", {{var}});',\n\t\t\t},\n\t\t},\n\t},\n}\n```\n\n### Status line\nThis function returns number of log statements by `nvim-chainsaw` in the current\nbuffer, for use in your status line.\n\n```lua\nrequire(\"chainsaw.visuals.statusline\").countInBuffer()\n```\n\n## Comparison with similar plugins\n\n\u003c!-- LTeX: enabled=false --\u003e\n|                                                   | nvim-chainsaw                                                                                          | debugprint.nvim                                                           | timber.nvim                                                     |\n| ------------------------------------------------- | ------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------- | --------------------------------------------------------------- |\n| log types                                         | variables, objects, asserts, types, sound, stacktraces, emoji, messages, debugger, time, clear-console | variables                                                                 | variables, objects, time                                        |\n| builtin language support                          | ~20                                                                                                    | ~35                                                                       | ~15                                                             |\n| inheritance of log statements from superset langs | ✅                                                                                                      | ✅                                                                         | ❌                                                               |\n| delete all log statements                         | ✅                                                                                                      | ✅                                                                         | ✅                                                               |\n| comment all log statements                        | ❌                                                                                                      | ✅                                                                         | ✅                                                               |\n| protection to accidentally commit log statements  | via auto-installed pre-commit hook (opt-in)                                                            | ❌                                                                         | ❌                                                               |\n| log statement customization                       | line numbers, filenames, time, multi-line statements                                                   | line numbers+filename (location), nearby line snippet, unique counter     | line numbers, insertation location                              |\n| insertation location                              | below, treesitter-based adjustments for some languages                                                 | below, above                                                              | below, above, surround, operator, treesitter-based adjustments  |\n| variable detection                                | word under cursor, visual selection, treesitter-based selection                                        | word under cursor, operator, visual selection, treesitter-based selection | word under cursor, visual selection, treesitter-based selection |\n| dot-repeatability                                 | ✅                                                                                                      | ✅                                                                         | ✅                                                               |\n| visual emphasis of log statements                 | signcolumn, line-highlight, status line, scrollbar                                                      | ❌                                                                         | flash on inserting statement                                    |\n| extra features for `nvim_lua`                     | separate configuration, availability of global debugging function                                      | ❌                                                                         | ❌                                                               |\n| log file watcher                                  | ❌                                                                                                      | ❌                                                                         | ✅                                                               |\n| maintainability / efficiency                      | ~1000 LoC                                                                                              | ~1600 LoC                                                                 | ~4500 LoC (excluding tests)                                     |\n\u003c!-- LTeX: enabled=true --\u003e\n\n## About the developer\nIn my day job, I am a sociologist studying the social mechanisms underlying the\ndigital economy. For my PhD project, I investigate the governance of the app\neconomy and how software ecosystems manage the tension between innovation and\ncompatibility. If you are interested in this subject, feel free to get in touch.\n\nI also occasionally blog about vim: [Nano Tips for Vim](https://nanotipsforvim.prose.sh)\n\n- [Website](https://chris-grieser.de/)\n- [Mastodon](https://pkm.social/@pseudometa)\n- [ResearchGate](https://www.researchgate.net/profile/Christopher-Grieser)\n- [LinkedIn](https://www.linkedin.com/in/christopher-grieser-ba693b17a/)\n\n\u003ca href='https://ko-fi.com/Y8Y86SQ91' target='_blank'\u003e\u003cimg height='36'\nstyle='border:0px;height:36px;' src='https://cdn.ko-fi.com/cdn/kofi1.png?v=3'\nborder='0' alt='Buy Me a Coffee at ko-fi.com' /\u003e\u003c/a\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchrisgrieser%2Fnvim-chainsaw","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fchrisgrieser%2Fnvim-chainsaw","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchrisgrieser%2Fnvim-chainsaw/lists"}