TheLazyCat00/simple-format

github github
formatting
stars 4
issues 0
subscribers 1
forks 0
CREATED

UPDATED


simple-format

simple-format allows you to search and replace with highlight groups + regex, making it easy to create custom formatting rules. I created this plugin because I wanted a formatter that does not change the whole styling of my code but only removes unnecessary white space.

https://github.com/user-attachments/assets/600ed7a0-98ae-48b4-925f-b7dc9ac01fb9

Installation with lazy.nvim

simple-format does not automatically format on save. Instead, simple-format provides a replace function, which can be called when needed. This allows everybody to have their own formatting logic.

[!NOTE] The replace function only modifies the line under the cursor.

{
    "TheLazyCat00/simple-format",
    opts = {
        -- the anchors for search and replace
        -- use uncommon characters or sequences
        injectionOpeningAnchor = "\226\160\128",
        injectionClosingAnchor = "\226\160\129",

        -- the opening and closing tags for the search syntax
        groupStart = "<",
        groupEnd = ">",
    },
    config = function (_, opts)
        local replace = require("simple-format").replace
        replace.setup(opts)

        -- add your own formatting logic
        -- remember to use vim.schedule to prevent neovim from freezing briefly
    end
}

You can also also use the reveal function to inspect the line and see what you need to search for (shown later in my personal config).

{
    -- HACK: use uncommon characters as anchors
    injectionOpeningAnchor = "\226\160\128",
    injectionClosingAnchor = "\226\160\129",
    groupStart = "<",
    groupEnd = ">",
}

My personal config

With this config, the plugin always formats when I leave insert mode.

{
    "TheLazyCat00/simple-format",
    event = "BufReadPost",
    opts = {},
    config = function (_, opts)
        local simpleFormat = require("simple-format")
        simpleFormat.setup(opts)
        local replace = simpleFormat.replace

        local function format()
            vim.schedule(function ()
                replace("(<.->) *(<|operator|=.->)","%1 %2")
                replace("(<|operator|=.->) *(<.->)","%1 %2")

                replace("(<.->) *(<|punctuation.delimiter|=,>)", "%1%2")
                replace("(<|punctuation.delimiter|=,>) *(<.->)", "%1 %2")

                replace("(<.-|punctuation.bracket|.-={>) *(<.-|punctuation.bracket|.-=}>)", "%1%2")
                replace("(<.-|punctuation.bracket|.-={>) *(<.*>) *(<.-|punctuation.bracket|.-=}>)","%1 %2 %3")

                replace("(<|punctuation.bracket|=%(>) *(.-) *(<|punctuation.bracket|=%)>)","%1%2%3")
            end)
        end

        vim.api.nvim_create_autocmd("InsertLeave", {
            callback = format,
        })

        vim.api.nvim_create_user_command("Reveal", simpleFormat.reveal, {})
    end
}

Syntax

The syntax for the search and replace arguments have the same syntax as str:gsub in lua. The only difference is that you can also use highlight groups like operator for pattern matching. The syntax goes: groupStart + highlightGroups + "=" + desiredValue + groupEnd. highlightGroups always have | on both the left and right side. So if a word is an operator and a punctuation.bracket the highlightGroups looks like this: |operator|punctuation.bracket|. Let's imagine this "word" would be +. In that case the whole "identifier" would look like this: <|operator|punctuation.bracket|=+>

With the defaults you could for example do <operator=.->. This would match any operator. Here we use regex functionality .- so that we can match for any operator. There are great online resources for learning regex, it's not as hard as it looks. We could also do <operator==>. This would match any operator that has = as its value.

[!TIP] To see the highlight group under the cursor, do :Inspect.

Examples

These are some useful examples you can use for your own config (assuming you are using the defaults).

  • Formatting lists by putting a space after ,:
    replace("(<|punctuation.delimiter|=,>) *(<.->)", "%1 %2")
    -- Explanation: We wanna search for a punctuation delimiter with
    -- the value ",".
    -- Note that we added .-| and |.- on both sides
    -- so that this works on words with multiple highlight groups
    -- (remember, ".-" matches any string and also empty strings,
    -- so this would work even with only punctuation.delimiter)
    
    -- We need to capture this, so that we can use the value in the replace process:
    -- We do this by putting it in parentheses.
    -- Then we search for a character that is not a white space:
    -- %S means anything that's NOT a white space character (notice the uppercase S).
    -- We also capture this value for later use.
    
    -- Then we replace the string with "%1 %2".
    -- This means that we take capture group 1, put a space and add group 2.
    -- NOTE: Groups get labeled automatically in regex according to the order.
    
  • Removing spaces between arguments and parentheses:
    -- We need to escape parentheses
    replace("(<|punctuation.bracket|=%(>) *(.-) *(<|punctuation.bracket|=%)>)","%1%2%3")
    

Contributions are welcome! Feel free to open issues or submit pull requests.