https://github.com/chrisgrieser/nvim-chainsaw
Smart and highly customizable insertion of various kinds of log statements.
Science Score: 46.0%
This score indicates how likely this project is to be science-related based on various indicators:
-
○CITATION.cff file
-
✓codemeta.json file
Found codemeta.json file -
✓.zenodo.json file
Found .zenodo.json file -
○DOI references
-
✓Academic publication links
Links to: researchgate.net -
✓Committers with academic emails
1 of 13 committers (7.7%) from academic institutions -
○Institutional organization owner
-
○JOSS paper metadata
-
○Scientific vocabulary similarity
Low similarity (10.3%) to scientific vocabulary
Keywords
Keywords from Contributors
Repository
Smart and highly customizable insertion of various kinds of log statements.
Basic Info
Statistics
- Stars: 125
- Watchers: 2
- Forks: 15
- Open Issues: 0
- Releases: 0
Topics
Metadata Files
README.md
nvim-chainsaw 🪚
Smart and highly customizable insertion of various kinds of log statements.
https://github.com/chrisgrieser/nvim-chainsaw/assets/73286100/fa55ae24-deba-4fed-84e9-554d9a695ad9
Table of Contents
- Features
- Installation
- Built-in language support
- Usage
- Configuration
- Comparison with similar plugins
- About the developer
Features
- Quick insertion of log statements for the variable under the cursor (normal mode) or the selection (visual mode).
- Smart detection of the variable under the cursor and the correct insertion location of the log statement via Treesitter.
- Commands for a dozen different log statement types, including assert statements, stack traces, or acoustic logging.
- All commands are dot-repeatable.
- Built-in support for ~20 languages. Easy configuration for additional languages.
- Flexible templating options for customizing log statements, including support for multi-line templates.
- Special support and utilities for
nvim-lua. - Helper commands to remove all log statements created by
nvim-chainsawor to clear the console. - Status line component to display the count of log statements in the current buffer. In addition, visual indication of log statements via line-highlights, signcolumn, or scrollbar (when using satellite.nvim).
- Auto-install a pre-commit hook that prevents committing files with the log
statements created by
nvim-chainsaw(opt-in).
Installation
Requirements - nvim 0.10+ - Treesitter parser for the languages you with this plugin
```lua -- lazy.nvim { "chrisgrieser/nvim-chainsaw", event = "VeryLazy", opts = {} -- required even if left empty },
-- packer use { "chrisgrieser/nvim-chainsaw" config = function () require("chainsaw").setup() end, } ```
Note that the .setup() call (or lazy.nvim's opts) is required, even if
called without options.
Built-in language support
- JavaScript (+ Typescript, Svelte, React)
- Python
- Lua (+ special considerations for
nvim-lua[^1]) - bash, zsh, fish
- AppleScript
- C++
- Ruby
- Rust
- CSS^2
- Go[^3]
- Swift
[!NOTE] Not every language supports every type of log statement. For the statements used, see log-statements-data.lua.
[^1]: nvim_lua uses log statements that inspect objects and is designed to
work with various notification plugins like nvim-notify, snacks.nvim, or
noice.nvim.
[^2]: Uses statements such as outline: 2px solid red !important; that are the
somewhat similar logging.
[^3]: The fmt package needs to be imported manually.
Usage
List of commands
The plugin offers various types of log statements. Bind keymaps for the ones you want to use.
All operations are dot-repeatable.
```lua -- log the name & value of the variable under the cursor require("chainsaw").variableLog()
-- like variableLog, but with syntax specific to inspect an object, for example
-- console.log(JSON.stringify(foobar)) in javascript
require("chainsaw").objectLog()
-- inspect the type of the variable under cursor, such as typeof foo in js
require("chainsaw").typeLog()
-- assertion statement for variable under cursor require("chainsaw").assertLog()
-- Minimal log statement, with an emoji for differentiation. Intended for -- control flow inspection, that is to quickly glance whether a condition was -- triggered or not. require("chainsaw").emojiLog()
-- Sound-playing statement for audible debugging. -- Depending on the type of log statement, it is either a terminal bell -- (requiring the terminal) or a system sound. -- Inspired by https://news.ycombinator.com/item?id=41519046 require("chainsaw").sound()
-- create log statement, and position the cursor to enter a message require("chainsaw").messageLog()
-- 1st call: start measuring the time -- 2nd call: log the time duration since the 1st statement require("chainsaw").timeLog()
-- debug statements like debugger in javascript or breakpoint() in python
require("chainsaw").debugLog()
-- prints the stacktrace of the current call require("chainsaw").stacktraceLog()
-- clearing statement, such as console.clear()
require("chainsaw").clearLog()
-- remove all log statements or all log statements in visually selected region -- created by nvim-chainsaw require("chainsaw").removeLogs() ```
These features can also be accessed with the user command :Chainsaw. Each
option corresponds to the commands above. For example, :Chainsaw
variableLog is same as :lua require("chainsaw").variableLog().
When using lua functions, variableLog, objectLog, typeLog, and assertLog
can also be used in visual mode to use the visual selection instead of the
word under the cursor. removeLogs can also be used in visual mode to only
remove log statements inside the selected lines.
Smart variable detection
When the variable under the cursor is an object with fields, chainsaw attempts
to automatically select the correct field. (Note that this feature requires the
Treesitter parser of the respective language.)
```lua myVariable.myF[i]eld = "foobar" -- prints: myVariable.myField
myVa[r]iable.myField = "foobar" -- prints: myVariable ```
Filetypes currently supporting this feature:
- Lua (and nvim_lua)
- Python
- JavaScript (and supersets)
PRs adding support for more languages are welcome. See smart-var-detect.lua.
Smart insertion location
chainsaw by default inserts the log statement below the cursor. The insertion
location is automatically adapted if doing would result in invalid code. (Note
that this feature requires the Treesitter parser of the respective language.)
```lua -- [] marks the cursor position
-- default behavior local f[o]obar = 1 -- will insert log statement here, below the cursor line
-- multi-line assignments local f[o]o = { bar = 1 } -- will insert log statement, here after the assignment
-- returns statements local function foobar() -- will insert log statement here, before the return return f[o]o end ```
Filetypes currently supporting this feature:
- Lua (and nvim_lua)
- JavaScript (and supersets)
PRs adding support for more languages are welcome. See smart-insert-location.lua.
List all log statements in the project
Since all log statements are marked with a specific string, you list easily use
any picker plugin to list and navigate to log statements across your project.
For example, when using snacks.nvim
with ripgrep:
lua
local marker = require("chainsaw.config.config").config.marker
require("snacks").picker.grep_word {
title = marker .. " log statements",
cmd = "rg",
args = { "--trim" },
search = marker,
regex = false,
live = false,
}
Configuration
The setup() call is required.
Basic configuration
``lua
-- default settings
require("chainsaw").setup {
-- The marker should be a unique string, since signs and highlights are based
-- on it. Furthermore,.removeLogs()` will remove any line with it. Thus,
-- unique emojis or strings (e.g., "[Chainsaw]") are recommended.
marker = "🪚",
-- Appearance of lines with the marker
visuals = {
icon = "", ---@type string|false as opposed to the marker only used in nvim, thus nerdfont glyphs are okay
signHlgroup = "DiagnosticSignInfo", ---@type string|false
signPriority = 50,
lineHlgroup = false, ---@type string|false
nvimSatelliteIntegration = {
enabled = true,
hlgroup = "DiagnosticSignInfo",
icon = "▪",
leftOfScrollbar = false,
priority = 40, -- compared to other handlers (diagnostics are 50)
},
},
-- Auto-install a pre-commit hook that prevents commits containing the marker
-- string. Will not be installed if there is already another pre-commit-hook.
preCommitHook = {
enabled = false,
notifyOnInstall = true,
hookPath = ".chainsaw", -- relative to git root
-- Will insert the marker as `%s`. (Pre-commit hooks requires a shebang
-- and exit non-zero when marker is found to block the commit.)
hookContent = [[#!/bin/sh
if git grep --fixed-strings --line-number "%s" .; then
echo
echo "nvim-chainsaw marker found. Aborting commit."
exit 1
fi
]],
-- Relevant if you track your nvim-config via git and use a custom marker,
-- as your config will then always include the marker and falsely trigger
-- the pre-commit hook.
notInNvimConfigDir = true,
-- List of git roots where the hook should not be installed. Supports
-- globs and `~`. Must match the full directory.
dontInstallInDirs = {
-- "~/special-project"
-- "~/repos/**",
},
},
-- configuration for specific logtypes
logTypes = {
emojiLog = {
emojis = { "🔵", "🟩", "⭐", "⭕", "💜", "🔲" },
},
},
-----------------------------------------------------------------------------
-- see https://github.com/chrisgrieser/nvim-chainsaw/blob/main/lua/chainsaw/config/log-statements-data.lua
logStatements = require("chainsaw.config.log-statements-data").logStatements,
supersets = require("chainsaw.config.log-statements-data").supersets,
} ```
Customize log statements via templates
New log statements can be added, and existing log statements can be modified
under the config logStatements. See
log-statements-data.lua for
the built-in log statements as reference. PRs adding log statements for more
languages are welcome.
There are various placeholders that are dynamically replaced:
- {{marker}} inserts the value from config.marker. Each log statement should
have one, so that the line can be removed via .removeLogs().
- {{var}}: variable as described further above.
- {{time}}: timestamp formatted as HH:MM:SS (for millisecond-precision, use
.timeLog() instead)
- {{filename}}: basename of the current file
- {{lnum}}: current line number
- {{insert}}: will enter insert mode at this location; by default used in
assertLog and messageLog. (For multi-line statements only works on the
last line.)
- .emojiLog() only: {{emoji}} inserts the emoji
- .timeLog() only: {{index}} inserts a running index. (Needed to
differentiate between variables when using timeLog multiple times).
lua
require("chainsaw").setup ({
logStatements = {
variableLog = {
javascript = 'console.log("{{marker}} {{var}}:", {{var}});',
yourFiletype = "", -- <-- add the statement for your filetype here
},
-- the same for the other log statement operations
},
})
[!NOTE] The strings may not include line breaks. If you want to use multi-line log statements, use a list of strings instead, each string representing one line.
The global pretty-logging function Chainsaw()
The plugin provides a globally accessible function Chainsaw(), specifically
designed for debugging nvim_lua. Given a variable, it pretty-prints the
variable, its name, and the location of the log statement call, all in a much
more concise manner.
Requirements: A notification plugin like
nvim-notify or
snacks.nvim. Syntax highlighting inside
the notification requires snacks.nvim.
Setup: You can use it by setting a custom log statement like this:
lua
require("chainsaw").setup {
logStatements = {
variableLog = {
nvim_lua = "Chainsaw({{var}}) -- {{marker}}",
},
},
}
[!TIP] To use
Chainsaw()during or shortly after startup, you may not lazy-loadnvim-chainsaw. Usinglazy.nvim, setlazy = falseand if neededpriority = 200to ensure the plugin loads before other start-plugins.
The lua_ls diagnostic undefined-global for Chainsaw can be disabled with
one of the following methods:
Options
```lua -- Option 1: nvim-lspconfig require("lspconfig").lua_ls.setup { settings = { Lua = { diagnostics = { globals = { "Chainsaw", "vim" }, }, }, }, } ``` ```jsonc // Option 2: .luarc.json { "diagnostics": { "globals": ["Chainsaw", "vim"], }, } ``` ```lua -- Option 3: lazydev.nvim opts = { library = { { path = "nvim-chainsaw", words = { "Chainsaw" } }, }, }, ```Make the formatter ignore the log statements
A common problem is that formatters like prettier split up the log statements
into multiple lines, making them hard to read and breaking .removeLogs(), which
relies on each line containing the marker emoji.
The simplest method to deal with this is to customize the log statement in your
configuration to include an ignore-comment: /* prettier-ignore */
- The log statements do not accept lines, but you can use a list of strings,
where each element is one line.
- Add the marker to the added line as well, so it is included in the removal by
.removeLogs().
lua
require("chainsaw").setup {
logStatements = {
variableLog = {
javascript = {
"/* prettier-ignore */ // {{marker}}",
'console.log("{{marker}} {{var}}:", {{var}});',
},
},
},
}
Status line
This function returns number of log statements by nvim-chainsaw in the current
buffer, for use in your status line.
lua
require("chainsaw.visuals.statusline").countInBuffer()
Comparison with similar plugins
| | nvim-chainsaw | debugprint.nvim | timber.nvim |
| ------------------------------------------------- | ------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------- | --------------------------------------------------------------- |
| log types | variables, objects, asserts, types, sound, stacktraces, emoji, messages, debugger, time, clear-console | variables | variables, objects, time |
| built-in language support | ~20 | ~35 | ~15 |
| inheritance of log statements from superset langs | ✅ | ✅ | ❌ |
| delete all log statements | ✅ | ✅ | ✅ |
| comment all log statements | ❌ | ✅ | ✅ |
| protection to accidentally commit log statements | via auto-installed pre-commit hook (opt-in) | ❌ | ❌ |
| log statement customization | line numbers, filenames, time, multi-line statements | line numbers+filename (location), nearby line snippet, unique counter | line numbers, insertation location |
| insertation location | below, treesitter-based adjustments for some languages | below, above | below, above, surround, operator, treesitter-based adjustments |
| 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 |
| dot-repeatability | ✅ | ✅ | ✅ |
| visual emphasis of log statements | signcolumn, line-highlight, status line, scrollbar | ❌ | flash on inserting statement |
| extra features for nvim_lua | separate configuration, availability of global debugging function | ❌ | ❌ |
| log file watcher | ❌ | ❌ | ✅ |
| maintainability / efficiency | ~1000 LoC | ~1600 LoC | ~4500 LoC (excluding tests) |
<!-- LTeX: enabled=true -->
About the developer
In my day job, I am a sociologist studying the social mechanisms underlying the digital economy. For my PhD project, I investigate the governance of the app economy and how software ecosystems manage the tension between innovation and compatibility. If you are interested in this subject, feel free to get in touch.
Owner
- Name: Chris Grieser
- Login: chrisgrieser
- Kind: user
- Location: Berlin, Germany
- Company: Technical University of Berlin
- Website: https://chris-grieser.de/
- Repositories: 189
- Profile: https://github.com/chrisgrieser
Researcher in sociology & software developer
GitHub Events
Total
- Issues event: 12
- Watch event: 28
- Delete event: 4
- Issue comment event: 45
- Push event: 244
- Pull request review event: 10
- Pull request review comment event: 12
- Pull request event: 23
- Fork event: 8
- Create event: 4
Last Year
- Issues event: 12
- Watch event: 28
- Delete event: 4
- Issue comment event: 45
- Push event: 244
- Pull request review event: 10
- Pull request review comment event: 12
- Pull request event: 23
- Fork event: 8
- Create event: 4
Committers
Last synced: 9 months ago
Top Committers
| Name | Commits | |
|---|---|---|
| Chris Grieser | 7****r | 379 |
| xlboy | x****8@f****m | 3 |
| Ishaan Kapoor | i****6@g****m | 2 |
| dependabot[bot] | 4****] | 2 |
| Andrew Ferrier | a****r | 2 |
| Vinesh Benny | v****y@m****a | 2 |
| al-ce | a****i@g****m | 1 |
| Tony Yunker | t****r@g****m | 1 |
| Naser Aleisa | a****r@g****m | 1 |
| Michael Chris Lopez | h****o@m****e | 1 |
| James G. Best | j****a | 1 |
| Brennen Puth | 9****h | 1 |
| 231tr0n | z****r@g****m | 1 |
Committer Domains (Top 20 + Academic)
Issues and Pull Requests
Last synced: 6 months ago
All Time
- Total issues: 12
- Total pull requests: 22
- Average time to close issues: 28 days
- Average time to close pull requests: about 9 hours
- Total issue authors: 9
- Total pull request authors: 12
- Average comments per issue: 2.08
- Average comments per pull request: 1.77
- Merged pull requests: 19
- Bot issues: 0
- Bot pull requests: 5
Past Year
- Issues: 6
- Pull requests: 16
- Average time to close issues: 23 days
- Average time to close pull requests: about 2 hours
- Issue authors: 5
- Pull request authors: 8
- Average comments per issue: 1.67
- Average comments per pull request: 1.81
- Merged pull requests: 13
- Bot issues: 0
- Bot pull requests: 5
Top Authors
Issue Authors
- skoch13 (2)
- hosman-nz (2)
- sQVe (1)
- 231tr0n (1)
- dlvhdr (1)
- SystematicError (1)
- andrewferrier (1)
- Pagliacii (1)
- mikeboiko (1)
- ishaan-kapoor (1)
Pull Request Authors
- dependabot[bot] (6)
- andrewferrier (4)
- ishaan-kapoor (4)
- VBenny42 (4)
- jim-at-jibba (3)
- brennenputh (2)
- mcchrish (2)
- xzbdmw (2)
- xlboy (2)
- al-ce (2)
- 231tr0n (2)
- ayunker (2)
- thenbe (1)
Top Labels
Issue Labels
Pull Request Labels
Dependencies
- actions/checkout v2 composite
- kdheepak/panvimdoc main composite
- stefanzweifel/git-auto-commit-action v4 composite
- amannn/action-semantic-pull-request v5 composite
- actions/stale v8 composite
- JohnnyMorganz/stylua-action v2 composite
- actions/checkout v3 composite