debugprint.nvim

Debugging in NeoVim the print() way!

MIT License

Stars
312
Committers
13

debugprint.nvim

Overview

debugprint is a NeoVim plugin that simplifies debugging for those who prefer a low-tech approach. Instead of using a sophisticated debugger like nvim-dap, some people prefer using a 'print' statement to trace the output during execution. With debugprint, you can insert 'print' statements, with debug information pre-populated, relevant to the language you're editing. These statements can include variable values.

debugprint supports 30 filetypes/programming languages out-of-the-box, including Python, JavaScript/TypeScript, Java, C/C++ and more. See the comparison table for the full list. It can also be extended to support other languages.

Features

debugprint is inspired by vim-debugstring; updated for the NeoVim generation. It:

  • Includes reference information in each 'print line' such as file names, line numbers, a counter, and snippets of other lines to make it easier to cross-reference them in output.

  • Can output the value of variables (or in some cases, expressions).

  • Dot-repeats.

  • Can detect a Treesitter variable name under the cursor for some languages, or will prompt with a sensible default. It understands Treesitter embedded languages (e.g. JavaScript-in-HTML).

  • Provides keymappings for normal, visual, and operator-pending modes.

  • Provides commands to delete debugging lines added to the current buffer or comment/uncomment those lines.

  • Can optionally move to the inserted line (or not).

  • Can be extended to add support for languages it doesn't support out of the box, or customize languages already supported (some ideas for this are show in the showcase).

  • Is MIT Licensed.

Demo

Installation

Requires NeoVim 0.9+.

Example for lazy.nvim:

return {
    "andrewferrier/debugprint.nvim",

    -- opts = { โ€ฆ },

    dependencies = {
        "echasnovski/mini.nvim" -- Needed for :ToggleCommentDebugPrints (not needed for NeoVim 0.10+)
    },
}

Example for packer.nvim:

packer.startup(function(use)
    โ€ฆ
    use({
        "andrewferrier/debugprint.nvim",
        config = function()
            opts = { โ€ฆ }
            require("debugprint").setup(opts)
        end,
        requires = {
            "echasnovski/mini.nvim" -- Needed for :ToggleCommentDebugPrints (not needed for NeoVim 0.10+)
        }
    })
    โ€ฆ
end)

The sections below detail the allowed options that can appear in the opts object.

There is a showcase of example debugprint configurations here which can be dropped into your configuration files to further enhance your use of debugprint.

Please subscribe to this GitHub issue to be notified of any breaking changes to debugprint.

Keymappings and Commands

By default, the plugin will create some keymappings and commands for use 'out of the box'. There are also some function invocations which are not mapped to any keymappings or commands by default, but could be. This is all shown in the following table.

Mode Default Key / Cmd Purpose Above/Below Line
Normal g?p Plain debug Below
Normal g?P Plain debug Above
Normal g?v Variable debug Below
Normal g?V Variable debug Above
Normal None Variable debug (always prompt for variable) Below
Normal None Variable debug (always prompt for variable) Above
Normal None Delete debug lines in buffer -
Normal None Comment/uncomment debug lines in buffer -
Visual g?v Variable debug Below
Visual g?V Variable debug Above
Op-pending g?o Variable debug Below
Op-pending g?O Variable debug Above
Command :DeleteDebugPrints Delete debug lines in buffer -
Command :ToggleCommentDebugPrints Comment/uncomment debug lines in buffer -

The keys and commands outlined above can be specifically overridden using the keymaps and commands objects inside the opts object used above during configuration of debugprint. For example, if configuring via lazy.nvim, it might look like this:

return {
    "andrewferrier/debugprint.nvim",
    opts = {
        keymaps = {
            normal = {
                plain_below = "g?p",
                plain_above = "g?P",
                variable_below = "g?v",
                variable_above = "g?V",
                variable_below_alwaysprompt = nil,
                variable_above_alwaysprompt = nil,
                textobj_below = "g?o",
                textobj_above = "g?O",
                toggle_comment_debug_prints = nil,
                delete_debug_prints = nil,
            },
            visual = {
                variable_below = "g?v",
                variable_above = "g?V",
            },
        },
        commands = {
            toggle_comment_debug_prints = "ToggleCommentDebugPrints",
            delete_debug_prints = "DeleteDebugPrints",
        },
    },
}

You only need to include the keys / commands which you wish to override, others will default as shown above. Setting any key or command to nil will skip it.

The default keymappings are chosen specifically because ordinarily in NeoVim they are used to convert sections to ROT-13, which most folks don't use.

Mapping Deprecation

Note: as of version 2.0.0, the old mechanism of configuring keymaps/commands which specifically allowed for mapping directly to require('debugprint').debugprint(...) is no longer officially supported or documented. This is primarily because of confusion which arose over how to do this mapping. Existing mappings performed this way are likely to continue to work for some time. You should, however, migrate over to the new method outlined above. If this doesn't give you the flexibility to map how you wish for some reason, please open an issue.

Other Options

debugprint supports the following options in its global opts object:

Option Default Purpose
move_to_debugline false When adding a debug line, moves the cursor to that line
display_counter true Whether to display/include the increasing integer counter in each debug message. Can also be set to a function to customize, see below
display_snippet true Whether to include a snippet of the line above/below in plain debug lines
filetypes See below Custom filetypes - see below
print_tag DEBUGPRINT The string inserted into each print statement, which can be used to uniquely identify statements inserted by debugprint.

Customizing Counter Logic

display_counter can also be set to a custom callback function to implement custom counter logic. In this case you are responsible for implementing your own counter. For example, this logic will implement essentially the same as the default counter:

local counter = 0

local counter_func = function()
    counter = counter + 1
    return '[' .. tostring(counter) .. ']'
end

debugprint.setup({display_counter = counter_func})

Add Custom Filetypes

Note: If you work out a configuration for a filetype not supported out-of-the-box, it would be appreciated if you can open an issue to have it supported out-of-the-box in debugprint so others can benefit. Similarly, if you spot any issues with, or improvements to, the language configurations out-of-the-box, please open an issue also.

If debugprint doesn't support your filetype, you can add it as a custom filetype in one of two ways:

  • In the opts.filetypes object in setup().

  • Using the require('debugprint').add_custom_filetypes() method (designed for use from ftplugin/ directories, etc.

In either case, the format is the same. For example, if adding via setup():

local my_fileformat = {
    left = 'print "',
    left_var = 'print "', -- `left_var` is optional, for 'variable' lines only; `left` will be used if it's not present
    right = '"',
    mid_var = "${",
    right_var = '}"',
}

require('debugprint').setup({ filetypes = { ["filetype"] = my_fileformat, ["another_filetype"] = another_of_my_fileformats, ... }})

or add_custom_filetypes():

require('debugprint').add_custom_filetypes({ my_fileformat, ... })

Your new file format will be merged in with those that already exist. If you pass in one that already exists, your configuration will override the built-in configuration.

The keys in the configuration are used like this:

Debug line type Default keys How debug line is constructed
Plain debug line g?p/g?P my_fileformat.left .. "auto-gen DEBUG string" .. my_fileformat.right
Variable debug line g?v/g?V/g?o/g?O my_fileformat.left_var (or my_fileformat.left) .. "auto-gen DEBUG string, variable=" .. my_file_format.mid_var .. variable .. my_fileformat.right_var

If it helps to understand these, you can look at the built-in configurations in filetypes.lua.

Known Limitations

  • debugprint does not handle deleting reformatted debug lines where a
    formatter has split them across multiple lines. If you want to be able to easily
    delete your debug lines using DeleteDebugPrints or similar, don't format your
    file between inserting them and running this command. See this
    issue
    for
    discussion on this.

Feature Comparison with Similar Plugins

(This table is quite wide, you may need to scroll horizontally)

Feature debugprint.nvim nvim-chainsaw printer.nvim refactoring.nvim vim-printer logsitter
Auto-generation of debug line, incl. locator info ๐Ÿ‘ โŒ ๐Ÿ‘ ๐Ÿ‘ โŒ ๐Ÿ‘
Print plain debug lines ๐Ÿ‘ ๐Ÿ‘ โŒ ๐Ÿ‘ โŒ โŒ
Print variables using current word/heuristic ๐Ÿ‘ ๐Ÿ‘ โŒ โŒ ๐Ÿ‘ โŒ
Print variables using treesitter ๐Ÿ‘ ๐Ÿ‘ โŒ ๐Ÿ‘ โŒ โŒ
Print variables/expressions using prompts ๐Ÿ‘ โŒ โŒ โŒ โŒ โŒ
Print variables using motions ๐Ÿ‘ โŒ ๐Ÿ‘ โŒ โŒ โŒ
Print variables using visual mode ๐Ÿ‘ ๐Ÿ‘ ๐Ÿ‘ ๐Ÿ‘ ๐Ÿ‘ โŒ
Print assertions โŒ ๐Ÿ‘ โŒ โŒ โŒ โŒ
Print stack traces โŒ ๐Ÿ‘ โŒ โŒ โŒ โŒ
Add time-tracking logic โŒ ๐Ÿ‘ โŒ โŒ โŒ โŒ
Add debugging breakpoints โŒ ๐Ÿ‘ โŒ โŒ โŒ โŒ
Print debug lines above/below current line ๐Ÿ‘ โŒ (via global config) โŒ ๐Ÿ‘ โŒ
Supports dot-repeat ๐Ÿ‘ ๐Ÿ‘ โŒ โŒ โŒ โŒ
Can control whether to move to inserted lines ๐Ÿ‘ โŒ โŒ โŒ โŒ โŒ
Clean up all debug lines ๐Ÿ‘ ๐Ÿ‘ โŒ โŒ โŒ โŒ
Comment/uncomment all debug lines ๐Ÿ‘ โŒ โŒ โŒ โŒ โŒ
Can put debugprint text into default register โŒ โŒ ๐Ÿ‘ โŒ โŒ โŒ
Built-in support for: - - - - - -
AppleScript ๐Ÿ‘ ๐Ÿ‘ โŒ โŒ โŒ โŒ
bash/sh ๐Ÿ‘ ๐Ÿ‘ ๐Ÿ‘ โŒ ๐Ÿ‘ โŒ
C ๐Ÿ‘ โŒ โŒ โŒ โŒ โŒ
C# ๐Ÿ‘ โŒ โŒ โŒ โŒ โŒ
C++ ๐Ÿ‘ โŒ ๐Ÿ‘ ๐Ÿ‘ ๐Ÿ‘ โŒ
CMake ๐Ÿ‘ โŒ โŒ โŒ โŒ โŒ
dart ๐Ÿ‘ โŒ โŒ โŒ โŒ โŒ
Docker ๐Ÿ‘ โŒ โŒ โŒ โŒ โŒ
DOS/Windows Batch ๐Ÿ‘ โŒ โŒ โŒ โŒ โŒ
Elixir ๐Ÿ‘ โŒ โŒ โŒ โŒ โŒ
fish ๐Ÿ‘ โŒ โŒ โŒ โŒ โŒ
Fortran ๐Ÿ‘ โŒ โŒ โŒ ๐Ÿ‘ โŒ
Golang ๐Ÿ‘ โŒ ๐Ÿ‘ ๐Ÿ‘ ๐Ÿ‘ ๐Ÿ‘
Haskell ๐Ÿ‘ โŒ โŒ โŒ โŒ โŒ
Java ๐Ÿ‘ โŒ ๐Ÿ‘ ๐Ÿ‘ ๐Ÿ‘ โŒ
Javascript/Typescript ๐Ÿ‘ ๐Ÿ‘ ๐Ÿ‘ ๐Ÿ‘ ๐Ÿ‘ ๐Ÿ‘
Kotlin ๐Ÿ‘ โŒ โŒ โŒ โŒ โŒ
lean ๐Ÿ‘ โŒ โŒ โŒ โŒ โŒ
lua ๐Ÿ‘ ๐Ÿ‘ ๐Ÿ‘ ๐Ÿ‘ ๐Ÿ‘ ๐Ÿ‘
GNU Make ๐Ÿ‘ โŒ โŒ โŒ โŒ โŒ
Perl ๐Ÿ‘ โŒ โŒ โŒ โŒ โŒ
PHP ๐Ÿ‘ โŒ โŒ ๐Ÿ‘ โŒ โŒ
Powershell/ps1 ๐Ÿ‘ โŒ โŒ โŒ โŒ โŒ
Python ๐Ÿ‘ ๐Ÿ‘ ๐Ÿ‘ ๐Ÿ‘ ๐Ÿ‘ โŒ
R ๐Ÿ‘ โŒ โŒ โŒ โŒ โŒ
Ruby ๐Ÿ‘ ๐Ÿ‘ โŒ ๐Ÿ‘ โŒ โŒ
Rust ๐Ÿ‘ ๐Ÿ‘ ๐Ÿ‘ โŒ ๐Ÿ‘ โŒ
Swift ๐Ÿ‘ โŒ โŒ โŒ โŒ โŒ
VimL (vimscript) ๐Ÿ‘ โŒ ๐Ÿ‘ โŒ ๐Ÿ‘ โŒ
zsh ๐Ÿ‘ โŒ ๐Ÿ‘ โŒ ๐Ÿ‘ โŒ
Add custom filetypes (doced/supported) ๐Ÿ‘ ๐Ÿ‘ ๐Ÿ‘ โŒ โŒ ๐Ÿ‘
Customizable callback formatter โŒ โŒ ๐Ÿ‘ โŒ โŒ โŒ
Implemented in Lua Lua Lua Lua VimL Lua

Other similar plugins (less popular or unmaintained):