Skip to content

Neovim Plugin for running functions on nodes.

Notifications You must be signed in to change notification settings

lkhphuc/ts-node-action

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

52 Commits
 
 
 
 
 
 
 
 

Repository files navigation

TS Node Action

A framework for running functions on Tree-sitter nodes, and updating the buffer with the result.

cycle case

multiline

condition formatting

ternerizing

operator flipflop

split join blocks

Installation

Lazy.nvim:

{
    'ckolkey/ts-node-action',
     dependencies = { 'nvim-treesitter' },
     config = function() -- Optional
         require("ts-node-action").setup({})
     end
},

packer:

use({
    'ckolkey/ts-node-action',
     requires = { 'nvim-treesitter' },
     config = function() -- Optional
         require("ts-node-action").setup({})
     end
})

Note: It's not required to call require("ts-node-action").setup() to initialize the plugin, but a table can be passed into the setup function to specify new actions for nodes or additional filetypes.

Usage

Bind require("ts-node-action").node_action to something. This is left up to the user.

For example, this would bind the function to K:

vim.keymap.set({ "n" }, "K", require("ts-node-action").node_action, { desc = "Trigger Node Action" })

Configuration

The setup() function accepts a table that conforms to the following schema:

{
    ['*'] = { -- Global table is checked for all filetypes
        ["node_type"] = fn,
        ...
    },
    filetype = {
        ["node_type"] = fn,
        ...
    },
    ...
}
  • filetype should be the value of vim.o.filetype, or '*' for the global table
  • node_type should be the value of vim.treesitter.get_node_at_cursor()

A definition on the filetype table will take precedence over the * (global) table.

Multiple Actions for a Node Type

To define multiple actions for a node type, structure your node_type value as a table of tables, like so:

["node_type"] = {
  { function_one, name = "Action One" },
  { function_two, name = "Action Two" },
}

vim.ui.select will use the value of name to when prompting you on which action to perform.

Writing your own Node Actions

All node actions should be a function that takes one argument: the tree-sitter node under the cursor.

You can read more about their API via :help tsnode

This function can return one or two values:

  • The first being the text to replace the node with. The replacement text can be either a "string" or { "table", "of", "strings" }. With a table of strings, each string will be on it's own line.

  • The second (optional) returned value is a table of options with a cursor or callback key. Both are optional. Here's how that can look.

{ cursor = { row = 0, col = 0 }, callback = function() }

or (equivalent to above)

{ cursor = {}, callback = function() }

If the cursor key is present with an empty table value, the cursor will be moved to the start of the line where the current node is (row = 0 col = 0 relative to node start_row and start_col).

If callback is present, it will simply get called without arguments after the buffer has been updated, and after the cursor has been positioned.

Here's a simplified example of how a node-action function gets called:

local action = node_actions[vim.o.filetype][node:type()]
local replacement, opts = action(node)
replace_node(node, replacement, opts or {})

API

require("ts-node-action").node_action()

Main function for plugin. Should be assigned by user, and when called will attempt to run the assigned function for the node your cursor is currently on.


require("ts-node-action").debug()

Prints some helpful information about the current node, as well as the loaded node actions for all filetypes

Helpers

require("ts-node-action.helpers").node_text(node)

@node: tsnode
@return: string

Returns the text of the specified node.


require("ts-node-action.helpers").multiline_node(node)

@node: tsnode
@return: boolean

Returns true if node spans multiple lines, and false if it's a single line.


require("ts-node-action.helpers").indent_text(text, indent, offset)

@text: string
@indent: number|tsnode
@offset: number|nil
@return: string

Returns the text (string) left padded by the indent amount. If indent is a tsnode, use it's starting column value. offset can be used to increase/decrease indentation, but is optional.


require("ts-node-action.helpers").indent_node_text(node, offset)

@node: tsnode
@offset: number|nil
@return: string

Returns the node text left padded by whitespace to match it's start_column position in the buffer. offset can be used to increase/decrease indentation, but is optional.


require("ts-node-action.helpers").padded_node_text(node, padding)

@node: tsnode
@padding: table
@return: string

For formatting unnamed tsnodes. For example, if you pass in an unnamed node representing the text ,, you could pass in a padding table (below) to add a trailing whitespace to , nodes.

{ [","] = "%s " }

Nodes not specified in table are returned unchanged.

Builtin Actions

Global (Applies to all filetypes)

{
  ["true"]       = toggle_boolean,
  ["false"]      = toggle_boolean,
  ["identifier"] = cycle_case,
}

Ruby

{
  ["true"]              = toggle_boolean,
  ["false"]             = toggle_boolean,
  ["array"]             = toggle_multiline,
  ["hash"]              = toggle_multiline,
  ["argument_list"]     = toggle_multiline,
  ["method_parameters"] = toggle_multiline,
  ["identifier"]        = cycle_case,
  ["constant"]          = cycle_case,
  ["block"]             = toggle_block,
  ["do_block"]          = toggle_block,
  ["binary"]            = toggle_operator,
  ["if"]                = handle_conditional,
  ["unless"]            = handle_conditional,
  ["if_modifier"]       = multiline_conditional,
  ["unless_modifier"]   = multiline_conditional,
  ["conditional"]       = expand_ternary,
  ["pair"]              = toggle_hash_style,
}

JSON

{
  ["object"] = toggle_multiline,
  ["array"]  = toggle_multiline,
}

Lua

{
  ["table_constructor"] = toggle_multiline,
  ["arguments"]         = toggle_multiline,
  ["true"]              = toggle_boolean,
  ["false"]             = toggle_boolean,
  ["identifier"]        = cycle_case,
}

Javascript

{
  ["object"]              = toggle_multiline,
  ["array"]               = toggle_multiline,
  ["statement_block"]     = toggle_multiline,
  ["identifier"]          = cycle_case,
  ["property_identifier"] = cycle_case,
  ["true"]                = toggle_boolean,
  ["false"]               = toggle_boolean,
}

Python

{
  ["dictionary"] = toggle_multiline,
  ["list"]       = toggle_multiline,
  ["true"]       = toggle_boolean,
  ["false"]      = toggle_boolean,
  ["identifier"] = cycle_case,
}

Contributing

If you come up with something that would be a good fit, pull requests for node actions are welcome!

Visit: https://www.github.com/ckolkey/ts-node-action

About

Neovim Plugin for running functions on nodes.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • Lua 100.0%