{"id":13412930,"url":"https://github.com/ckolkey/ts-node-action","last_synced_at":"2025-05-16T01:06:29.178Z","repository":{"id":65375765,"uuid":"583765500","full_name":"CKolkey/ts-node-action","owner":"CKolkey","description":"Neovim Plugin for running functions on nodes.","archived":false,"fork":false,"pushed_at":"2025-01-23T21:12:18.000Z","size":275,"stargazers_count":373,"open_issues_count":15,"forks_count":21,"subscribers_count":6,"default_branch":"master","last_synced_at":"2025-05-12T02:53:30.741Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Lua","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/CKolkey.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"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}},"created_at":"2022-12-30T21:04:02.000Z","updated_at":"2025-04-27T02:20:57.000Z","dependencies_parsed_at":"2023-11-13T12:25:55.283Z","dependency_job_id":"cc793a6a-3600-4bce-94a3-74bf911d4f5d","html_url":"https://github.com/CKolkey/ts-node-action","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CKolkey%2Fts-node-action","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CKolkey%2Fts-node-action/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CKolkey%2Fts-node-action/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CKolkey%2Fts-node-action/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/CKolkey","download_url":"https://codeload.github.com/CKolkey/ts-node-action/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254448579,"owners_count":22072764,"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":[],"created_at":"2024-07-30T20:01:31.253Z","updated_at":"2025-05-16T01:06:24.165Z","avatar_url":"https://github.com/CKolkey.png","language":"Lua","readme":"# TS Node Action\n\nA framework for running functions on Tree-sitter nodes, and updating the buffer\nwith the result.\n\n\u003c!-- mdformat-toc start --slug=github --no-anchors --maxlevel=3 --minlevel=2 --\u003e\n\n- [Installation](#installation)\n- [Usage](#usage)\n- [Configuration](#configuration)\n  - [Multiple Actions for a Node Type](#multiple-actions-for-a-node-type)\n- [Writing your own Node Actions](#writing-your-own-node-actions)\n  - [Options](#options)\n- [API](#api)\n- [null-ls Integration](#null-ls-integration)\n- [Helpers](#helpers)\n- [Builtin Actions](#builtin-actions)\n- [Testing](#testing)\n- [Contributing](#contributing)\n\n\u003c!-- mdformat-toc end --\u003e\n\n![cycle case](https://user-images.githubusercontent.com/7228095/210154055-8851210e-e8e1-4ba3-a474-0be373df8d1b.gif)\n\n![multiline](https://user-images.githubusercontent.com/7228095/210153839-5009dbed-db7a-4b1c-b5c9-879b90f32a64.gif)\n\n![condition formatting](https://user-images.githubusercontent.com/7228095/210153712-8be29018-00a3-427f-8a59-959e705e12c6.gif)\n\n![ternerizing](https://user-images.githubusercontent.com/7228095/210153716-2fde6101-352b-4ef9-ba00-0842e6749201.gif)\n\n![operator flipflop](https://user-images.githubusercontent.com/7228095/210153726-3f5da644-ae1f-4288-b52b-e12a9c757293.gif)\n\n![split join blocks](https://user-images.githubusercontent.com/7228095/210153731-a2c2a717-e7ae-4330-9664-11ba4ed3c005.gif)\n\n## Installation\n\n`Lazy.nvim`:\n\n```lua\n{\n    'ckolkey/ts-node-action',\n     opts = {},\n},\n```\n\n`packer`:\n\n```lua\nuse({\n    'ckolkey/ts-node-action',\n     config = function()\n         require(\"ts-node-action\").setup({})\n     end\n})\n```\n\n\u003e \\[!NOTE\\]\n\u003e It's not required to call `require(\"ts-node-action\").setup()` to\n\u003e initialize the plugin, but a table can be passed into the setup function to\n\u003e specify new actions for nodes or additional langs.\n\n## Usage\n\nBind `require(\"ts-node-action\").node_action` to something. This is left up to\nthe user.\n\nFor example, this would bind the function to `K`:\n\n```lua\nvim.keymap.set(\n    { \"n\" },\n    \"K\",\n    require(\"ts-node-action\").node_action,\n    { desc = \"Trigger Node Action\" },\n)\n```\n\nIf `tpope/vim-repeat` is installed, calling `node_action()` is dot-repeatable.\n\nIf `setup()` is called, user commands `:NodeAction` and `:NodeActionDebug` are\ndefined.\n\nSee `available_actions()` below for how to set this up with LSP Code Actions.\n\n## Configuration\n\nThe `setup()` function accepts a table that conforms to the following schema:\n\n```lua\n{\n    ['*'] = { -- Global table is checked for all langs\n        [\"node_type\"] = fn,\n        ...\n    },\n    lang = {\n        [\"node_type\"] = fn,\n        ...\n    },\n    ...\n}\n```\n\n- `lang` should be the treesitter parser lang, or `'*'` for the global table\n- `node_type` should be the value of `vim.treesitter.get_node_at_cursor()`\n\nA definition on the `lang` table will take precedence over the `*` (global)\ntable.\n\n### Multiple Actions for a Node Type\n\nTo define multiple actions for a node type, structure your `node_type` value as\na table of tables, like so:\n\n```lua\n[\"node_type\"] = {\n  { function_one, name = \"Action One\" },\n  { function_two, name = \"Action Two\" },\n}\n```\n\n`vim.ui.select` will use the value of `name` to when prompting you on which\naction to perform.\n\nIf you want to bypass `vim.ui.select` and instead just want all actions to be\napplied without prompting, you can pass `ask = false` as an argument in the\n`node_type` value. Using the same example as above, it would look like this:\n\n```lua\n[\"node_type\"] = {\n  { function_one, name = \"Action One\" },\n  { function_two, name = \"Action Two\" },\n  ask = false,\n}\n```\n\n## Writing your own Node Actions\n\nAll node actions should be a function that takes one argument: the tree-sitter\nnode under the cursor.\n\nYou can read more about their API via `:help tsnode`\n\nThis function can return one or two values:\n\n- The first being the text to replace the node with. The replacement text can be\n  either a `\"string\"` or `{ \"table\", \"of\", \"strings\" }`. With a table of\n  strings, each string will be on it's own line.\n\n- The second (optional) returned value is a table of options. Supported keys\n  are: `cursor`, `callback`, `format`, and `target`.\n\nHere's how that can look.\n\n```lua\n{\n  cursor   = { row = 0, col = 0 },\n  callback = function() ... end,\n  format   = true,\n  target   = \u003ctsnode\u003e\n}\n```\n\n### Options\n\n#### `cursor`\n\nIf the `cursor` key is present with an empty table value, the cursor will be\nmoved to the start of the line where the current node is (`row = 0` `col = 0`\nrelative to node `start_row` and `start_col`).\n\n#### `callback`\n\nIf `callback` is present, it will simply get called without arguments after the\nbuffer has been updated, and after the cursor has been positioned.\n\n#### `format`\n\nBoolean value. If `true`, will run `=` operator on new buffer text. Requires\n`indentexpr` to be set.\n\n#### `target`\n\nTSNode or list of TSNodes. If present, this node will be used as the target for replacement instead\nof the node under your cursor.\nIf list of nodes their combined range will be used for replacement. Note that in this case if the target nodes specified are not next to each other, any thing in between will also be replaced.\n\nHere's a simplified example of how a node-action function gets called:\n\n```lua\nlocal action = node_actions[lang][node:type()]\nlocal replacement, opts = action(node)\nreplace_node(node, replacement, opts or {})\n```\n\n## API\n\n`require(\"ts-node-action\").node_action()` Main function for plugin. Should be\nassigned by user, and when called will attempt to run the assigned function for\nthe node your cursor is currently on.\n\n______________________________________________________________________\n\n`require(\"ts-node-action\").debug()` Prints some helpful information about the\ncurrent node, as well as the loaded node actions for all langs\n\n______________________________________________________________________\n\n`require(\"ts-node-action\").available_actions()` Exposes the function assigned to\nthe node your cursor is currently on, as well as its name\n\n______________________________________________________________________\n\n## null-ls Integration\n\nUsers can set up integration with\n[null-ls](https://github.com/jose-elias-alvarez/null-ls.nvim) and use it to\ndisplay available node actions by registering the builtin `ts_node_action` code\naction source\n\n```lua\nlocal null_ls = require(\"null-ls\")\nnull_ls.setup({\n  sources = {\n    null_ls.builtins.code_actions.ts_node_action,\n    ...\n  }\n})\n```\n\nThis will present the available node action(s) for the node under your cursor\nalongside your `lsp`/`null-ls` code actions.\n\n______________________________________________________________________\n\n## Helpers\n\n```lua\nrequire(\"ts-node-action.helpers\").node_text(node)\n```\n\n```lua\n@node: tsnode\n@return: string\n```\n\nReturns the text of the specified node.\n\n______________________________________________________________________\n\n```lua\nrequire(\"ts-node-action.helpers\").node_is_multiline(node)\n```\n\n```lua\n@node: tsnode\n@return: boolean\n```\n\nReturns true if node spans multiple lines, and false if it's a single line.\n\n______________________________________________________________________\n\n```lua\nrequire(\"ts-node-action.helpers\").padded_node_text(node, padding)\n```\n\n```lua\n@node: tsnode\n@padding: table\n@return: string\n```\n\nFor formatting unnamed tsnodes. For example, if you pass in an unnamed node\nrepresenting the text `,`, you could pass in a `padding` table (below) to add a\ntrailing whitespace to `,` nodes.\n\n```lua\n{ [\",\"] = \"%s \" }\n```\n\nNodes not specified in table are returned unchanged.\n\n## Builtin Actions\n\n\u003cdetails\u003e\n\u003c!-- markdownlint-disable-next-line no-inline-html --\u003e\n\u003csummary\u003e\u003ch3\u003eCycle Case\u003c/h3\u003e\u003c/summary\u003e\n\n```lua\nrequire(\"ts-node-action.actions\").cycle_case(formats)\n```\n\n```lua\n@param formats table|nil\n```\n\n`formats` param can be a table of strings specifying the different formats to\ncycle through. By default it's\n\n```lua\n{ \"snake_case\", \"pascal_case\", \"screaming_snake_case\", \"camel_case\" }\n```\n\nA table can also be used in place of a string to implement a custom formatter.\nEvery format is a table that implements the following interface:\n\n- pattern (string)\n- apply (function)\n- standardize (function)\n\n#### `pattern` \u003c!-- markdownlint-disable-line header-increment --\u003e\n\nA Lua pattern (string) that matches the format\n\n#### `apply`\n\nA function that takes a _table_ of standardized strings as it's argument, and\nreturns a _string_ in the format\n\n#### `standardize`\n\nA function that takes a _string_ in this format, and returns a table of strings,\nall lower case, no special chars. ie:\n\n```lua\n    standardize(\"ts_node_action\") -\u003e { \"ts\", \"node\", \"action\" }\n    standardize(\"tsNodeAction\")   -\u003e { \"ts\", \"node\", \"action\" }\n    standardize(\"TsNodeAction\")   -\u003e { \"ts\", \"node\", \"action\" }\n    standardize(\"TS_NODE_ACTION\") -\u003e { \"ts\", \"node\", \"action\" }\n```\n\n\u003e \\[!NOTE\\]\n\u003e The order of formats can be important, as some identifiers are the same\n\u003e for multiple formats. Take the string 'action' for example. This is a match for\n\u003e both snake*case \\_and* camel_case. It's therefore important to place a format\n\u003e between those two so we can correctly change the string.\n\n______________________________________________________________________\n\n\u003c/details\u003e\n\nBuiltin actions are all higher-order functions so they can easily have options\noverridden on a per-lang basis. Check out the implementations under\n`lua/filetypes/` to see how!\n\n\u003c!-- markdownlint-disable line-length --\u003e\n\n|                            | (\\*) | Ruby | js/ts/tsx/jsx | Lua | Python | PHP | Rust | C#  | JSON | HTML | YAML | R   |\n| -------------------------- | ---- | ---- | ------------- | --- | ------ | --- | ---- | --- | ---- | ---- | ---- | --- |\n| `toggle_boolean()`         | ✅    | ✅    | ✅             | ✅   | ✅      | ✅   | ✅    | ✅    |      |      | ✅    | ✅   |\n| `cycle_case()`             | ✅    | ✅    | ✅             | ✅   | ✅      | ✅   | ✅    | ✅    |      |      |      | ✅   |\n| `cycle_quotes()`           | ✅    | ✅    | ✅             | ✅   | ✅      | ✅   |      |      |      |      |      | ✅   |\n| `toggle_multiline()`       |      | ✅    | ✅             | ✅   | ✅      | ✅   |  ✅   |      | ✅    |      |      | ✅   |\n| `toggle_operator()`        |      | ✅    | ✅             | ✅   | ✅      | ✅   |       |   ✅  |      |      |      | ✅   |\n| `toggle_int_readability()` |      | ✅    | ✅             |     | ✅      | ✅   | ✅     | ✅    | ✅    |      |      |     |\n| `toggle_block()`           |      | ✅    |               |     |        |     |       |      |      |      |      |     |\n| if/else \\\u003c-\u003e ternary       |      | ✅    |               |     | ✅      |     |      |      |      |      |      |     |\n| if block/postfix           |      | ✅    |               |     |        |     |      |      |      |      |      |     |\n| `toggle_hash_style()`      |      | ✅    |               |     |        |     |      |      |      |      |      |     |\n| `conceal_string()`         |      |      | ✅             |     |        |     |      |      |      | ✅    |      |     |\n\n\u003c!-- markdownlint-enable line-length --\u003e\n\n## Testing\n\nTo run the test suite, clone the repo and run `./run_spec`. It should pull all\ndependencies into `spec/support/` on first run, then execute the tests.\n\nThis is still a little WIP.\n\n## Contributing\n\nIf you come up with something that would be a good fit, pull requests for node\nactions are welcome!\n\nVisit: \u003chttps://www.github.com/ckolkey/ts-node-action\u003e\n","funding_links":[],"categories":["Editing Support"],"sub_categories":["Scrollbar"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fckolkey%2Fts-node-action","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fckolkey%2Fts-node-action","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fckolkey%2Fts-node-action/lists"}