Skip to content

Commit

Permalink
feat: add command :SosBufToggle to toggle buffers
Browse files Browse the repository at this point in the history
This command allows for ignoring individual buffers so that they do not
get autosaved. It accepts an optional `[bufname]` argument to specify a
buffer other than the current one. Deleting a buffer (e.g. `:bdelete`)
resets its ignored status. Ignore status is stored in the buffer
variable `b:sos_ignore`.

Also add dedicated API functions for this, as well as functions to
enable or disable the entire plugin. These can all be found in the
`require('sos')` module table.

Also do some refactoring/cleanup:

- Rename `lua/bufevents.lua` -> `lua/observer.lua`
- Remove `lua/plugin.lua` (require main module instead)
- Main module `require('sos')` is now the entry point (incl. when the
  plugin is sourced by nvim at startup) and also holds most of the
  plugin's state
- Make all config fields optional (in the class/type)
- Update `init.lua` to handle module reloading (UNFINISHED)
- Update `util.lua` with new utility functions and error handling
- Improve benchmark interface
  • Loading branch information
tmillr committed Sep 13, 2024
1 parent 0351264 commit 2943f26
Show file tree
Hide file tree
Showing 22 changed files with 930 additions and 474 deletions.
1 change: 0 additions & 1 deletion .luarc.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
{
"$schema": "https://raw.githubusercontent.com/sumneko/vscode-lua/master/setting/schema.json",
"Lua.runtime.version": "LuaJIT",
"Lua.diagnostics.globals": ["vim"],
"Lua.diagnostics.unusedLocalExclude": ["_*", "api"],
"workspace.ignoreDir": ["tests", "_test", "perf"],
"workspace.checkThirdParty": false
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,8 @@ If you have Neovim setup to format on save/write via autocmds, you may experienc

TODO: provide (better) fix or suggestions, finish this section

In the meantime, if you are having issues due to a format-on-save setup and until a better solution is discovered, you can try:
In the meantime, if you are having issues due to a format-on-save setup, and until a better solution is discovered, you can try:

- changing which autocmd/event triggers autoformatting (e.g. use `InsertLeave` instead)
- disabling format-on-save altogether

Expand All @@ -179,4 +180,3 @@ In the meantime, if you are having issues due to a format-on-save setup and unti
[prs]: /../../pulls
[q&a]: /../../discussions/categories/q-a
[undotree]: ../../../../mbbill/undotree
[^1]: djdjdjdj
2 changes: 2 additions & 0 deletions TODO.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,3 +106,5 @@
file/buf the err msg is for).

- [ ] feat: opt (and maybe cmd/func) to disable timer

- [ ] Calling `setup()` should reset timer if it is active?
42 changes: 42 additions & 0 deletions lua/sos/_test/action.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
local asrt = require 'sos._test.assert'
local util = require 'sos._test.util'
local api = vim.api
local M = { buf = {} }

function M.input(keys)
api.nvim_feedkeys(
api.nvim_replace_termcodes(keys, true, true, true),
-- 'mtx',
'L',
false
)

util.await_schedule()
end

function M.cmd(cmd)
asrt.normal_mode_nonblocking()
M.input(':' .. cmd .. '<CR>')
asrt.normal_mode_nonblocking()
end

---NOTE: May change the current buffer!
function M.trigger_save(buf)
if buf and buf ~= 0 and buf ~= api.nvim_get_current_buf() then
assert(api.nvim_buf_is_valid(buf), 'invalid buffer number: ' .. buf)
local ei = vim.o.ei
vim.o.ei = 'all'
api.nvim_set_current_buf(buf)
vim.o.ei = ei
end

M.cmd 'tabnew'
end

function M.buf.modify()
assert.is_false(vim.bo.mod, 'buffer is already modified')
M.input 'ochanges<Esc>'
assert.is_true(vim.bo.mod, 'modification unsuccessful')
end

return M
44 changes: 44 additions & 0 deletions lua/sos/_test/assert.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
local api = vim.api
local M = {}

function M.normal_mode_nonblocking(mode)
local m = mode or api.nvim_get_mode()
assert.equals('n', m.mode, 'not in regular normal mode')
assert.is_false(api.nvim_get_mode().blocking, 'mode is blocking')
end

-- function M.all_bufs_saved()
-- assert.same(
-- {},
-- vim.fn.getbufinfo { bufmodified = 1 },
-- 'all buffers should be saved, and none modified'
-- )
-- end

---@param buf number
function M.saved(buf)
vim.validate { buf = { buf, { 'number' }, false } }
local file = api.nvim_buf_get_name(buf)
assert.is_false(vim.bo[buf].mod, 'buffer is still modified')
assert.same(
api.nvim_buf_get_lines(buf, 0, -1, true),
vim.fn.readfile(file),
"buffer wasn't saved"
)
end

---@param buf number
function M.unsaved(buf)
vim.validate { buf = { buf, { 'number' }, false } }
local file = api.nvim_buf_get_name(buf)
assert.is_true(vim.bo[buf].mod, "buffer shouldn't have been saved")
local ok, content = pcall(vim.fn.readfile, file)
if not ok then return end
assert.not_same(
api.nvim_buf_get_lines(buf, 0, -1, true),
content,
"buffer shouldn't have been saved"
)
end

return M
86 changes: 41 additions & 45 deletions lua/sos/_test/util.lua
Original file line number Diff line number Diff line change
Expand Up @@ -2,43 +2,51 @@
-- dirs for each test type (e2e, unit, etc.) so things are better organized,
-- re-usable fn for testing autoread/checktime

local M = {}
local api = vim.api
local uv = vim.loop
local sleep = uv.sleep
local co = coroutine
local tmpfiles
local M = { assert = require 'sos._test.assert' }
local api, co, uv = vim.api, coroutine, vim.uv or vim.loop

---@param schedwrap boolean
function M.coroutine_resumer(schedwrap)
local curr_co = co.running()

if schedwrap then
return vim.schedule_wrap(function(...) co.resume(curr_co, ...) end)
end

return function(...) co.resume(curr_co, ...) end
local function resume(...) assert(co.resume(curr_co, ...)) end
return schedwrap and vim.schedule_wrap(resume) or resume
end

---@return nil
function M.await_schedule()
local curr_co = co.running()

local cur_co = co.running()
assert(cur_co, 'not running in coroutine')
local timeout = M.set_timeout(
5000,
function()
co.resume(curr_co, false, 'timed out waiting for vim.schedule() callback')
assert(
co.resume(
cur_co,
false,
'timed out waiting for vim.schedule() callback'
)
)
end
)

vim.schedule(function()
timeout:stop()
co.resume(curr_co, true)
co.resume(cur_co, true)
end)

assert(co.yield())
end

---Sleep/wait (pause execution) by yielding the current coroutine. In contrast
---to `vim.wait()` and `uv.sleep()`, this will pause the current lua "thread"
---only while still allowing nvim to run completely unhindered. Must be called
---in coroutine context.
---@param ms integer
function M.wait(ms)
vim.defer_fn(M.coroutine_resumer(false), ms)
co.yield()
end

---@async
function M.setup_plugin(...)
-- require("sos").setup(nil, true)
Expand All @@ -47,6 +55,7 @@ function M.setup_plugin(...)
else
require('sos').setup { enabled = true }
end

M.await_vim_enter()
end

Expand Down Expand Up @@ -74,18 +83,20 @@ function M.bufwritemock(onwrite)
})
end

---@return integer bufnr
---@return string output
---@overload fun(nvim: table, file?: string): string
---@overload fun(file?: string): string
---@overload fun(nvim: table, file?: string)
---@overload fun(file?: string)
function M.silent_edit(...)
local external_nvim_or_api, file = M.nvim_recv_or_api(...)

return external_nvim_or_api.nvim_cmd({
local out = external_nvim_or_api.nvim_cmd({
cmd = 'edit',
args = { file },
magic = { file = false, bar = false },
mods = { silent = true },
}, { output = true })

return api.nvim_get_current_buf(), out
end

---@param keys string
Expand All @@ -107,32 +118,15 @@ end
---@param content? string | (string|number)[]
---@return string fname
function M.tmpfile(content)
if not tmpfiles then
tmpfiles = {}

api.nvim_create_autocmd('VimLeave', {
pattern = '*',
desc = 'Cleanup temp files',
nested = false,
callback = function()
for _, f in ipairs(tmpfiles) do
vim.fn.delete(f)
end
end,
})
end

local tmp = vim.fn.tempname()
table.insert(tmpfiles, tmp)

assert(tmp and tmp ~= '', 'vim.fn.tempname() returned nil or empty string')

if content then
assert(
vim.fn.writefile(
type(content) == 'table' and content or { content },
tmp,
'b'
'bs'
) == 0,
'Error: file write failed'
)
Expand Down Expand Up @@ -250,15 +244,15 @@ function M.start_nvim(opts)

do
local ok
sleep(200)
M.wait(200)

for _ = 1, 4 do
ok, chan = pcall(
function() return vim.fn.sockconnect('pipe', sock_addr, { rpc = true }) end
)

if ok then break end
sleep(500)
M.wait(500)
end

assert(ok, chan)
Expand Down Expand Up @@ -295,6 +289,7 @@ function M.start_nvim(opts)
)
end

-- Where the magic happens!
setmetatable(self, {
__index = function(_, key)
return M[key]
Expand All @@ -310,7 +305,6 @@ function M.start_nvim(opts)
})

assert(self:eval 'v:vim_did_enter' == 1, 'ERROR: vim has not entered yet')

return self
end

Expand Down Expand Up @@ -363,7 +357,9 @@ function M.autocmd(autocmd, opts)

local timer = M.set_timeout(
1e4,
function() co.resume(co, false, 'timed out waiting for autocmd') end
function()
assert(co.resume(curr_co, false, 'timed out waiting for autocmd'))
end
)

local result = { co.yield() }
Expand All @@ -380,13 +376,13 @@ end
function M.await_vim_enter()
if vim.v.vim_did_enter == 1 or vim.v.vim_did_enter == true then return end
M.autocmd('VimEnter', { once = true }):await()
M.await_schedule()
M.wait(100)
end

---@param fn function
---@return number ns
function M.time_it_once(fn)
local hrtime = vim.loop.hrtime
local hrtime = uv.hrtime
local start = hrtime()
fn()
return hrtime() - start
Expand Down Expand Up @@ -427,7 +423,7 @@ end
---@param cb function
---@return unknown
function M.set_timeout(ms, cb)
local timer = vim.loop.new_timer()
local timer = uv.new_timer()

timer:start(ms, 0, function()
timer:stop()
Expand Down
1 change: 0 additions & 1 deletion lua/sos/autocmds.lua
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
local M = {}
local commands = require 'sos.commands'
local impl = require 'sos.impl'
local api = vim.api
local augroup = 'sos-autosaver'
Expand Down
Loading

0 comments on commit 2943f26

Please sign in to comment.