Skip to content
Draft
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
80 changes: 79 additions & 1 deletion lua/bullets/actions.lua
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,52 @@ local function feed(keys)
vim.api.nvim_feedkeys(vim.api.nvim_replace_termcodes(keys, true, false, true), "n", false)
end

local function style_enabled(marker)
for _, style in ipairs(config.options.list_item_styles) do
if style == marker then
return true
end

if style:sub(-1) == "+" and marker:match("^" .. vim.pesc(style:sub(1, -2)) .. "+$") then
return true
end
end

return false
end

local function parse_static(line)
local indent, marker, spacing, text = line:match("^(%s*)(\\item)(%s+)(.*)$")
if not marker then
indent, marker, spacing, text = line:match("^(%s*)(#%.)(%s+)(.*)$")
end
if not marker then
indent, marker, spacing, text = line:match("^(%s*)([%*.]+)(%s+)(.*)$")
if marker and (marker == "*" or not (marker:match("^%*+$") or marker:match("^%.+$"))) then
marker = nil
end
end
if not marker or not style_enabled(marker) then
return nil
end

return {
type = "static",
indent = indent,
marker = marker,
spacing = spacing,
text = text,
}
end

local function parse_standard(line)
local indent, marker, spacing, text = line:match("^(%s*)([-*+])(%s+)(.*)$")
if not marker then
return nil
end
if not style_enabled(marker) then
return nil
end

return {
indent = indent,
Expand Down Expand Up @@ -78,6 +119,11 @@ local function parse_roman(line)
end

local function parse_line(line)
local static = parse_static(line)
if static then
return { static }
end

local standard = parse_standard(line)
if standard then
standard.type = "std"
Expand Down Expand Up @@ -177,6 +223,14 @@ local function next_marker(bullet)
return bullet.marker
end

local function prefix_width(bullet)
if bullet.type == "num" or bullet.type == "abc" or bullet.type == "rom" then
return #bullet.indent + #bullet.marker + #bullet.closure + #bullet.spacing
end

return #bullet.indent + #bullet.marker + #bullet.spacing
end

local function next_prefix(bullet)
local marker = next_marker(bullet)
if not marker then
Expand All @@ -186,16 +240,40 @@ local function next_prefix(bullet)
if bullet.type == "std" then
return bullet.indent .. marker .. bullet.spacing
end
if bullet.type == "static" then
return bullet.indent .. marker .. bullet.spacing
end

local prefix = marker .. bullet.closure .. " "
return bullet.indent .. pad_right(prefix, #bullet.marker + #bullet.closure + #bullet.spacing)
end

local function wrapped_owner(lnum, line)
if not config.options.enable_wrapped_lines or line:match("^%s*$") then
return nil
end

local current_indent = #(line:match("^%s*") or "")
for row = lnum - 1, 1, -1 do
local previous_line = vim.api.nvim_buf_get_lines(0, row - 1, row, false)[1]
if previous_line:match("^%s*$") then
return nil
end

local previous_bullet = resolve_bullet(parse_line(previous_line), row)
if previous_bullet and current_indent >= prefix_width(previous_bullet) then
return previous_bullet
end
end

return nil
end

function M.insert_new_bullet()
local mode = vim.fn.mode()
local lnum = vim.api.nvim_win_get_cursor(0)[1]
local line = vim.api.nvim_get_current_line()
local bullet = resolve_bullet(parse_line(line), lnum)
local bullet = resolve_bullet(parse_line(line), lnum) or wrapped_owner(lnum, line)

if mode ~= "n" and not at_eol(line) then
feed("<CR>")
Expand Down
11 changes: 8 additions & 3 deletions test/asciidoc_spec.lua
Original file line number Diff line number Diff line change
@@ -1,20 +1,25 @@
local helpers = require("test.helpers")
local active_it = it
local it = pending

describe("AsciiDoc", function()
it("maintains indentation in ascii doc bullets", function()
before_each(function()
helpers.reset_config()
end)

active_it("maintains indentation in ascii doc bullets", function()
helpers.test_bullet_inserted(
"rats",
{ "= Pets!", "* dogs", "** cats" },
{ "= Pets!", "* dogs", "** cats", "** rats" }
)
end)

it("supports dot bullets", function()
active_it("supports dot bullets", function()
helpers.test_bullet_inserted("cats", { "= Pets!", ". dogs" }, { "= Pets!", ". dogs", ". cats" })
end)

it("supports nested dot bullets", function()
active_it("supports nested dot bullets", function()
helpers.test_bullet_inserted(
"rats",
{ "= Pets!", ". dogs", ".. cats" },
Expand Down
6 changes: 3 additions & 3 deletions test/bullets_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ describe("Bullets.vim", function()
)
end)

it("adds a new latex bullet", function()
active_it("adds a new latex bullet", function()
helpers.test_bullet_inserted("Second item", {
"\\documentclass{article}",
" \\begin{document}",
Expand All @@ -62,15 +62,15 @@ describe("Bullets.vim", function()
})
end)

it("adds a pandoc bullet if the prev line had one", function()
active_it("adds a pandoc bullet if the prev line had one", function()
helpers.test_bullet_inserted(
"second bullet",
{ "Hello there", "#. this is the first bullet" },
{ "Hello there", "#. this is the first bullet", "#. second bullet" }
)
end)

it("adds an Org mode bullet if the prev line had one", function()
active_it("adds an Org mode bullet if the prev line had one", function()
helpers.test_bullet_inserted(
"second bullet",
{ "Hello there", "**** this is the first bullet" },
Expand Down
1 change: 1 addition & 0 deletions test/helpers.lua
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ function M.reset_config()
checkbox_partials_toggle = 1,
outline_levels = { "ROM", "ABC", "num", "abc", "rom", "std-", "std*", "std+" },
enable_roman_list = true,
enable_wrapped_lines = true,
pad_right = true,
delete_last_bullet_if_empty = 1,
})
Expand Down
46 changes: 44 additions & 2 deletions test/wrapping_bullets_spec.lua
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
local helpers = require("test.helpers")
local active_it = it
local it = pending

describe("wrapped bullets", function()
it("inserts a new bullet after a wrapped bullet", function()
before_each(function()
helpers.reset_config()
end)

active_it("inserts a new bullet after a wrapped bullet", function()
helpers.test_bullet_inserted("do that", {
"# Hello there",
"- do this",
Expand All @@ -15,7 +20,24 @@ describe("wrapped bullets", function()
})
end)

it("does not insert wrapped bullets unnecessarily", function()
active_it("does not insert wrapped bullets when disabled", function()
require("bullets").setup({ enable_wrapped_lines = false })
helpers.new_buffer({
"# Hello there",
"- do this",
" this is the second line of the first bullet",
})
helpers.feedkeys("A<CR>")
helpers.feedkeys("ido that<Esc>")
assert.are.same({
"# Hello there",
"- do this",
" this is the second line of the first bullet",
"do that",
}, helpers.get_lines())
end)

active_it("does not insert wrapped bullets unnecessarily", function()
-- When <CR> is pressed on a non-bullet line the plugin defers the actual
-- newline via feedkeys('n'). Using two separate feedkeys calls ensures the
-- deferred CR fires (the 'x' flag drains it) before we type the next text.
Expand Down Expand Up @@ -43,4 +65,24 @@ describe("wrapped bullets", function()
"do that",
}, helpers.get_lines())
end)

active_it("does not insert wrapped bullets after whitespace-only separators", function()
helpers.new_buffer({
"# Hello there",
"- do this",
" this is the second line of the first bullet",
" ",
" no bullets after this line",
})
helpers.feedkeys("A<CR>")
helpers.feedkeys("ido that<Esc>")
assert.are.same({
"# Hello there",
"- do this",
" this is the second line of the first bullet",
" ",
" no bullets after this line",
"do that",
}, helpers.get_lines())
end)
end)