Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ After:
- **c++**: all C constructs, plus template parameters and arguments
- **nix**: lists
- **json**: objects, arrays
- **yaml**: flow sequences, flow mappings
- **yaml**: flow sequences, flow mappings, block sequences
- **jsdoc**: descriptions

### Adding a new language
Expand Down
5 changes: 4 additions & 1 deletion lua/splitjoin/languages/yaml/defaults.lua
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
local Yaml = require'splitjoin.languages.yaml.functions'

---@type SplitjoinLanguageConfig
return {

nodes = {
flow_sequence = { surround = { '[', ']' } },
flow_sequence = { surround = { '[', ']' }, split = Yaml.split_flow_sequence },
flow_mapping = { surround = { '{', '}' } },
block_sequence = { split = function() end, join = Yaml.join_block_sequence },
},

}
111 changes: 111 additions & 0 deletions lua/splitjoin/languages/yaml/functions.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
local Node = require'splitjoin.util.node'

local Yaml = {}

local function all_scalars(node)
return not Node.find_descendant(node, function(n)
if n == node then return false end
local t = n:type()
return t == 'flow_sequence' or t == 'flow_mapping'
end)
end

local function in_flow_context(node)
local parent = node:parent()
while parent do
local t = parent:type()
if t == 'flow_sequence' or t == 'flow_mapping' then
return true
end
parent = parent:parent()
end
return false
end

function Yaml.split_flow_sequence(node, options)
if not all_scalars(node) or in_flow_context(node) then
return Node.split(node, options)
end

local indent = options.default_indent or ' '
local items = {}
for child in node:iter_children() do
local t = child:type()
if t ~= '[' and t ~= ']' and t ~= ',' then
table.insert(items, vim.trim(Node.get_text(child)))
end
end

if #items == 0 then return end

local row, col, row_end, col_end = node:range()
local base_indent = Node.get_base_indent(node) or ''
local line = vim.api.nvim_buf_get_lines(0, row, row + 1, false)[1]
local before = line:sub(1, col)

local lines = {}
local start_col = col

if before:match(':%s*$') then
local content_len = #before:match('^(.-)%s*$')
start_col = content_len
table.insert(lines, '')
for _, item in ipairs(items) do
table.insert(lines, base_indent .. indent .. '- ' .. item)
end
else
for _, item in ipairs(items) do
table.insert(lines, base_indent .. '- ' .. item)
end
start_col = 0
end

vim.api.nvim_buf_set_text(0, row, start_col, row_end, col_end, lines)
if start_col == 0 then
pcall(vim.api.nvim_win_set_cursor, 0, { row + 1, #base_indent })
else
pcall(vim.api.nvim_win_set_cursor, 0, { row + 2, #(base_indent .. indent) })
end
end

function Yaml.join_block_sequence(node, options)
local items = {}
for child in node:iter_children() do
if child:type() == 'block_sequence_item' then
for grandchild in child:iter_children() do
if grandchild:type() ~= '-' then
local text = vim.trim(Node.get_text(grandchild))
if text ~= '' then
table.insert(items, text)
end
end
end
end
end

if #items == 0 then return end

local row, col, row_end, col_end = node:range()
local replacement = '[' .. table.concat(items, ', ') .. ']'

local line_count = vim.api.nvim_buf_line_count(0)
if row_end >= line_count then
row_end = line_count - 1
col_end = #vim.api.nvim_buf_get_lines(0, row_end, row_end + 1, false)[1]
end

if row > 0 then
local prev_line = vim.api.nvim_buf_get_lines(0, row - 1, row, false)[1]
local colon_pos = prev_line:find(':%s*$')
if colon_pos then
vim.api.nvim_buf_set_text(0, row - 1, colon_pos, row_end, col_end, { ' ' .. replacement })
pcall(vim.api.nvim_win_set_cursor, 0, { row, colon_pos + 1 })
return
end
end

vim.api.nvim_buf_set_text(0, row, col, row_end, col_end, { replacement })
pcall(vim.api.nvim_win_set_cursor, 0, { row + 1, col })
end

return Yaml
1 change: 1 addition & 0 deletions queries/yaml/splitjoin.scm
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
(flow_sequence) @splitjoin.target
(flow_mapping) @splitjoin.target
(block_sequence) @splitjoin.target
43 changes: 37 additions & 6 deletions test/yaml_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,51 @@ local lang = 'yaml'

describe(lang, function()

H.make_suite(lang, 'flow sequence',
H.make_suite(lang, 'flow sequence (scalar, block-style)',
d[[
list: [1, 2, 3]
]],
d[[
list: [
1,
2,
3,
]
list:
- 1
- 2
- 3
]],
'1'
)

H.make_suite(lang, 'flow sequence (non-scalar, bracket-style)',
d[=[
awful: [string, 0, {refactor: this}, pal]
]=],
d[=[
awful: [
string,
0,
{refactor: this},
pal,
]
]=],
'string'
)

H.make_suite(lang, 'flow sequence (nested indent)',
d[[
on:
pull_request:
types: [opened, synchronize, reopened]
]],
d[[
on:
pull_request:
types:
- opened
- synchronize
- reopened
]],
'opened'
)

H.make_suite(lang, 'flow mapping',
d[=[
map: {a: 1, b: 2}
Expand Down
Loading