style: apply markdown formatting

This commit is contained in:
cbows 2023-07-29 18:52:45 +02:00
parent 0cfc5b4121
commit b089a308b0
4 changed files with 200 additions and 92 deletions

9
.markdownlint.yaml Normal file
View file

@ -0,0 +1,9 @@
---
default: true
# MD033/no-inline-html
MD033:
allowed_elements:
- summary
- details
- a

View file

@ -4,3 +4,19 @@ repos:
rev: v0.18.1
hooks:
- id: stylua-github
- repo: https://github.com/executablebooks/mdformat
rev: 0.7.16
hooks:
- id: mdformat
additional_dependencies:
- mdformat-gfm
- mdformat-frontmatter
- mdformat-footnote
- mdformat-tables
- mdformat-toc
- repo: https://github.com/igorshubovych/markdownlint-cli
rev: v0.35.0
hooks:
- id: markdownlint-fix

View file

@ -1 +1,2 @@
rust 1.71.0
python 3.10.12

266
README.md
View file

@ -1,18 +1,24 @@
# TS Node Action
A framework for running functions on Tree-sitter nodes, and updating the buffer with the result.
A framework for running functions on Tree-sitter nodes, and updating the buffer
with the result.
- [Installation](https://github.com/CKolkey/ts-node-action/blob/master/README.md#installation)
- [Usage](https://github.com/CKolkey/ts-node-action/blob/master/README.md#usage)
- [Configuration](https://github.com/CKolkey/ts-node-action/blob/master/README.md#configuration)
- [Multiple Actions for a Node Type](https://github.com/CKolkey/ts-node-action/blob/master/README.md#multiple-actions-for-a-node-type)
- [Writing Your Own Actions](https://github.com/CKolkey/ts-node-action#writing-your-own-node-actions)
- [API](https://github.com/CKolkey/ts-node-action#writing-your-own-node-actions)
- [Helpers](https://github.com/CKolkey/ts-node-action#helpers)
- [Null-LS](https://github.com/CKolkey/ts-node-action#null-ls-integration)
- [Builtin Actions](https://github.com/CKolkey/ts-node-action#builtin-actions)
- [Testing](https://github.com/CKolkey/ts-node-action#testing)
- [Contributing](https://github.com/CKolkey/ts-node-action#contributing)
<!-- mdformat-toc start --slug=github --no-anchors --maxlevel=3 --minlevel=2 -->
- [Installation](#installation)
- [Usage](#usage)
- [Configuration](#configuration)
- [Multiple Actions for a Node Type](#multiple-actions-for-a-node-type)
- [Writing your own Node Actions](#writing-your-own-node-actions)
- [Options](#options)
- [API](#api)
- [null-ls Integration](#null-ls-integration)
- [Helpers](#helpers)
- [Builtin Actions](#builtin-actions)
- [Testing](#testing)
- [Contributing](#contributing)
<!-- mdformat-toc end -->
![cycle case](https://user-images.githubusercontent.com/7228095/210154055-8851210e-e8e1-4ba3-a474-0be373df8d1b.gif)
@ -29,6 +35,7 @@ A framework for running functions on Tree-sitter nodes, and updating the buffer
## Installation
`Lazy.nvim`:
```lua
{
'ckolkey/ts-node-action',
@ -38,6 +45,7 @@ A framework for running functions on Tree-sitter nodes, and updating the buffer
```
`packer`:
```lua
use({
'ckolkey/ts-node-action',
@ -48,21 +56,31 @@ use({
})
```
**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 langs.
> \[!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 langs.
## Usage
Bind `require("ts-node-action").node_action` to something. This is left up to the user.
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`:
```lua
vim.keymap.set({ "n" }, "K", require("ts-node-action").node_action, { desc = "Trigger Node Action" })
vim.keymap.set(
{ "n" },
"K",
require("ts-node-action").node_action,
{ desc = "Trigger Node Action" },
)
```
If `tpope/vim-repeat` is installed, calling `node_action()` is dot-repeatable.
If `setup()` is called, user commands `:NodeAction` and `:NodeActionDebug` are defined.
If `setup()` is called, user commands `:NodeAction` and `:NodeActionDebug` are
defined.
See `available_actions()` below for how to set this up with LSP Code Actions.
@ -87,11 +105,13 @@ The `setup()` function accepts a table that conforms to the following schema:
- `lang` should be the treesitter parser lang, or `'*'` for the global table
- `node_type` should be the value of `vim.treesitter.get_node_at_cursor()`
A definition on the `lang` table will take precedence over the `*` (global) table.
A definition on the `lang` 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:
To define multiple actions for a node type, structure your `node_type` value as
a table of tables, like so:
```lua
["node_type"] = {
@ -100,11 +120,12 @@ To define multiple actions for a node type, structure your `node_type` value as
}
```
`vim.ui.select` will use the value of `name` to when prompting you on which action to perform.
`vim.ui.select` will use the value of `name` to when prompting you on which
action to perform.
If you want to bypass `vim.ui.select` and instead just want all actions to be applied
without prompting, you can pass `ask = false` as an argument in the `node_type` value.
Using the same example as above, it would look like this:
If you want to bypass `vim.ui.select` and instead just want all actions to be
applied without prompting, you can pass `ask = false` as an argument in the
`node_type` value. Using the same example as above, it would look like this:
```lua
["node_type"] = {
@ -116,17 +137,19 @@ Using the same example as above, it would look like this:
## Writing your own Node Actions
All node actions should be a function that takes one argument: the tree-sitter node under the cursor.
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 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. Supported keys are: `cursor`, `callback`, `format`, and
`target`.
- The second (optional) returned value is a table of options. Supported keys
are: `cursor`, `callback`, `format`, and `target`.
Here's how that can look.
@ -139,21 +162,31 @@ Here's how that can look.
}
```
### Options
#### `cursor`
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 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`).
#### `callback`
If `callback` is present, it will simply get called without arguments after the buffer has been updated, and after the
cursor has been positioned.
If `callback` is present, it will simply get called without arguments after the
buffer has been updated, and after the cursor has been positioned.
#### `format`
Boolean value. If `true`, will run `=` operator on new buffer text. Requires `indentexpr` to be set.
Boolean value. If `true`, will run `=` operator on new buffer text. Requires
`indentexpr` to be set.
#### `target`
TSNode. If present, this node will be used as the target for replacement instead of the node under your cursor.
TSNode. If present, this node will be used as the target for replacement instead
of the node under your cursor.
Here's a simplified example of how a node-action function gets called:
```lua
local action = node_actions[lang][node:type()]
local replacement, opts = action(node)
@ -162,23 +195,28 @@ 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.
<hr>
`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 langs
<hr>
______________________________________________________________________
`require("ts-node-action").available_actions()`
Exposes the function assigned to the node your cursor is currently on, as well as its name
<hr>
`require("ts-node-action").debug()` Prints some helpful information about the
current node, as well as the loaded node actions for all langs
______________________________________________________________________
`require("ts-node-action").available_actions()` Exposes the function assigned to
the node your cursor is currently on, as well as its name
______________________________________________________________________
## null-ls Integration
Users can set up integration with [null-ls](https://github.com/jose-elias-alvarez/null-ls.nvim) and use it to display
available node actions by registering the builtin `ts_node_action` code action source
Users can set up integration with
[null-ls](https://github.com/jose-elias-alvarez/null-ls.nvim) and use it to
display available node actions by registering the builtin `ts_node_action` code
action source
```lua
local null_ls = require("null-ls")
@ -190,35 +228,53 @@ null_ls.setup({
})
```
This will present the available node action(s) for the node under your cursor alongside your `lsp`/`null-ls` code actions.
<hr>
This will present the available node action(s) for the node under your cursor
alongside your `lsp`/`null-ls` code actions.
______________________________________________________________________
## Helpers
`require("ts-node-action.helpers").node_text(node)`
```lua
require("ts-node-action.helpers").node_text(node)
```
```lua
@node: tsnode
@return: string
```
Returns the text of the specified node.
<hr>
`require("ts-node-action.helpers").node_is_multiline(node)`
Returns the text of the specified node.
______________________________________________________________________
```lua
require("ts-node-action.helpers").node_is_multiline(node)
```
```lua
@node: tsnode
@return: boolean
```
Returns true if node spans multiple lines, and false if it's a single line.
<hr>
`require("ts-node-action.helpers").padded_node_text(node, padding)`
Returns true if node spans multiple lines, and false if it's a single line.
______________________________________________________________________
```lua
require("ts-node-action.helpers").padded_node_text(node, padding)
```
```lua
@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.
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.
```lua
{ [","] = "%s " }
```
@ -228,68 +284,94 @@ Nodes not specified in table are returned unchanged.
## Builtin Actions
<details>
<summary>Cycle Case</summary>
`require("ts-node-action.actions").cycle_case(formats)`
<!-- markdownlint-disable-next-line no-inline-html -->
<summary><h3>Cycle Case</h3></summary>
```lua
require("ts-node-action.actions").cycle_case(formats)
```
```lua
@param formats table|nil
```
`formats` param can be a table of strings specifying the different formats to cycle through. By default it's `{
"snake_case", "pascal_case", "screaming_snake_case", "camel_case" }`.
`formats` param can be a table of strings specifying the different formats to
cycle through. By default it's
```lua
{ "snake_case", "pascal_case", "screaming_snake_case", "camel_case" }
```
A table can also be used in place of a string to implement a custom formatter.
Every format is a table that implements the following interface:
A table can also be used in place of a string to implement a custom formatter. Every format is a table that implements the following interface:
- pattern (string)
- apply (function)
- standardize (function)
### pattern
#### `pattern` <!-- markdownlint-disable-line header-increment -->
A Lua pattern (string) that matches the format
### apply
A function that takes a _table_ of standardized strings as it's argument, and returns a _string_ in the format
#### `apply`
### standardize
A function that takes a _string_ in this format, and returns a table of strings, all lower case, no special chars.
ie:
```
A function that takes a _table_ of standardized strings as it's argument, and
returns a _string_ in the format
#### `standardize`
A function that takes a _string_ in this format, and returns a table of strings,
all lower case, no special chars. ie:
```lua
standardize("ts_node_action") -> { "ts", "node", "action" }
standardize("tsNodeAction") -> { "ts", "node", "action" }
standardize("TsNodeAction") -> { "ts", "node", "action" }
standardize("TS_NODE_ACTION") -> { "ts", "node", "action" }
```
NOTE: The order of formats can be important, as some identifiers are the same for multiple formats.
Take the string 'action' for example. This is a match for both snake_case _and_ camel_case. It's
therefore important to place a format between those two so we can correcly change the string.
<hr />
> \[!NOTE\]
> The order of formats can be important, as some identifiers are the same
> for multiple formats. Take the string 'action' for example. This is a match for
> both snake*case \_and* camel_case. It's therefore important to place a format
> between those two so we can correcly change the string.
______________________________________________________________________
</details>
Builtin actions are all higher-order functions so they can easily have options overridden on a per-lang basis. Check out the implementations under `lua/filetypes/` to see how!
Builtin actions are all higher-order functions so they can easily have options
overridden on a per-lang basis. Check out the implementations under
`lua/filetypes/` to see how!
| | (*) | Ruby | js/ts/tsx/jsx | Lua | Python | PHP | Rust | JSON | HTML | YAML | R |
|---|---|---|---|---|---|---|---|---|---|---|---|
| `toggle_boolean()` | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | | | ✅ | ✅ |
| `cycle_case()` | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | | | | ✅ | ✅ |
| `cycle_quotes()` | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | | | | | ✅ |
| `toggle_multiline()` | | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | | | ✅ |
| `toggle_operator()` | | ✅ | ✅ | ✅ | ✅ | ✅ | | | | | ✅ |
| `toggle_int_readability()` | | ✅ | ✅ | | ✅ | ✅ | ✅ | ✅ | | | |
| `toggle_block()` | | ✅ | | | | | | | | | |
| if/else <-> ternery | | ✅ | | | ✅ | | | | | | |
| if block/postfix | | ✅ | | | | | | | | | |
| `toggle_hash_style()` | | ✅ | | | | | | | | | |
| `conceal_string()` | | | ✅ | | | | | | ✅ | | |
<!-- markdownlint-disable line-length -->
| | (\*) | Ruby | js/ts/tsx/jsx | Lua | Python | PHP | Rust | JSON | HTML | YAML | R |
| -------------------------- | ---- | ---- | ------------- | --- | ------ | --- | ---- | ---- | ---- | ---- | --- |
| `toggle_boolean()` | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | | | ✅ | ✅ |
| `cycle_case()` | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | | | | ✅ |
| `cycle_quotes()` | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | | | | | ✅ |
| `toggle_multiline()` | | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | | | ✅ |
| `toggle_operator()` | | ✅ | ✅ | ✅ | ✅ | ✅ | | | | | ✅ |
| `toggle_int_readability()` | | ✅ | ✅ | | ✅ | ✅ | ✅ | ✅ | | | |
| `toggle_block()` | | ✅ | | | | | | | | | |
| if/else \<-> ternery | | ✅ | | | ✅ | | | | | | |
| if block/postfix | | ✅ | | | | | | | | | |
| `toggle_hash_style()` | | ✅ | | | | | | | | | |
| `conceal_string()` | | | ✅ | | | | | | ✅ | | |
<!-- markdownlint-enable line-length -->
## Testing
To run the test suite, clone the repo and run `./run_spec`. It should pull all dependencies into `spec/support/` on
first run, then execute the tests.
To run the test suite, clone the repo and run `./run_spec`. It should pull all
dependencies into `spec/support/` on first run, then execute the tests.
This is still a little WIP.
## Contributing
If you come up with something that would be a good fit, pull requests for node actions are welcome!
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
Visit: <https://www.github.com/ckolkey/ts-node-action>