Skip to content

Commit f90a249

Browse files
committed
feat: initial commit
0 parents  commit f90a249

File tree

14 files changed

+341
-0
lines changed

14 files changed

+341
-0
lines changed

.editorconfig

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
root = true
2+
3+
[*]
4+
indent_style = space
5+
indent_size = 2
6+
end_of_line = lf
7+
charset = utf-8
8+
trim_trailing_whitespace = true
9+
insert_final_newline = true

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
node_modules/

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2021 Oskar Grunning
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# bufignore

lua/bufignore/config.lua

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
local defaults = require('bufignore.defaults')
2+
3+
--- @class Config
4+
--- @field private _user_config UserConfig
5+
local M = {}
6+
7+
M._user_config = nil
8+
9+
--- Gets the user's configuration.
10+
--- @return UserConfig config The current configuration.
11+
M.get_user_config = function()
12+
return M._user_config
13+
end
14+
15+
--- Sets up the configuration.
16+
--- @param overrides? UserConfig Configration which will override the defaults.
17+
--- @return UserConfig config The configuration.
18+
M.setup = function(overrides)
19+
M._user_config = vim.tbl_deep_extend('force', defaults, overrides or {})
20+
21+
return M._user_config
22+
end
23+
24+
return M

lua/bufignore/defaults.lua

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
--- @alias ConfigCallback fun(event: { bufnr: number, file_path: string }): boolean
2+
3+
--- @class UserConfig
4+
--- @field auto_start boolean
5+
--- @field callback ConfigCallback | false | nil TODO
6+
local defaults = {
7+
auto_start = true,
8+
callback = nil,
9+
}
10+
11+
return defaults

lua/bufignore/dispatcher.lua

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
local queue = require('bufignore.queue')
2+
3+
local augroup =
4+
vim.api.nvim_create_augroup('bufignore-augroup', { clear = true })
5+
6+
--- @class Dispatcher
7+
--- @field private _is_bound boolean
8+
local M = {}
9+
10+
M._is_bound = false
11+
12+
--- Binds event listeners for the plugin.
13+
M.bind_events = function()
14+
if not M._is_bound then
15+
-- Listen for `BufHidden` events and enqueue the file for
16+
-- processing.
17+
vim.api.nvim_create_autocmd('BufHidden', {
18+
group = augroup,
19+
callback = function(event)
20+
queue.enqueue_file(vim.fn.fnamemodify(event.file, ':p'))
21+
end,
22+
})
23+
24+
-- Listen for `DirChanged` events and enqueue all buffers for
25+
-- processing.
26+
vim.api.nvim_create_autocmd('DirChanged', {
27+
group = augroup,
28+
callback = function()
29+
local bufnrs = vim.api.nvim_list_bufs()
30+
31+
queue.clear_queue()
32+
for _, bufnr in ipairs(bufnrs) do
33+
queue.enqueue_file(vim.api.nvim_buf_get_name(bufnr))
34+
end
35+
end,
36+
})
37+
38+
M._is_bound = true
39+
end
40+
end
41+
42+
--- Unbinds event listeners for the plugin.
43+
M.unbind_events = function()
44+
if M._is_bound then
45+
vim.api.nvim_clear_autocmds({ group = augroup })
46+
47+
M._is_bound = false
48+
end
49+
end
50+
51+
return M

lua/bufignore/file-processor.lua

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
local config = require('bufignore.config')
2+
3+
--- @class FileProcessor
4+
local M = {}
5+
6+
--- Checks if a buffer meets the requirements for unlisting.
7+
--- @param bufnr number The buffer number.
8+
--- @param file_path string The path of the file associated with the buffer.
9+
--- @return boolean `true` if the buffer meets the unlisting requirements, otherwise `false`.
10+
M._is_valid_for_unlisting = function(bufnr, file_path)
11+
local user_config = config.get_user_config()
12+
13+
-- Buffer is not visible
14+
return vim.fn.bufwinid(bufnr) == -1
15+
-- Buffer is valid
16+
and vim.api.nvim_buf_is_valid(bufnr)
17+
-- Buffer is loaded
18+
and vim.api.nvim_buf_is_loaded(bufnr)
19+
-- Buffer is listed
20+
and vim.api.nvim_buf_get_option(bufnr, 'buflisted')
21+
-- User-defined callback is either falsy or returns true.
22+
and (
23+
not user_config.callback
24+
or user_config.callback({ bufnr = bufnr, file_path = file_path })
25+
)
26+
end
27+
28+
--- Unlists a buffer for an ignored file.
29+
--- @param file_path string The path of the ignored file.
30+
--- @private
31+
M._unlist_ignored_file = function(file_path)
32+
-- Schedules main event-loop invocation to preventing textlock issues.
33+
vim.schedule(function()
34+
---@diagnostic disable-next-line: param-type-mismatch
35+
local bufnr = vim.fn.bufnr(file_path)
36+
37+
if M._is_valid_for_unlisting(bufnr, file_path) then
38+
-- Unlist git ignored file buffer.
39+
vim.api.nvim_buf_set_option(bufnr, 'buflisted', false)
40+
end
41+
end)
42+
end
43+
44+
--- Unlists buffers for ignored files.
45+
---@param file_paths string[] The paths of the ignored files.
46+
M.unlist_ignored_files = function(file_paths)
47+
for _, file_path in ipairs(file_paths) do
48+
M._unlist_ignored_file(file_path)
49+
end
50+
end
51+
52+
return M

lua/bufignore/git.lua

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
local Job = require('plenary.job')
2+
3+
--- @class Git
4+
local M = {}
5+
6+
--- Checks if files are ignored by Git.
7+
--- @param file_paths string[] The list of file paths to check for ignore status.
8+
--- @param callback function The callback function that receives the ignored file paths.
9+
M.check_ignore = function(file_paths, callback)
10+
local args = { 'check-ignore' }
11+
12+
for _, file_path in ipairs(file_paths) do
13+
table.insert(args, file_path)
14+
end
15+
16+
-- Execute the Git command.
17+
Job:new({
18+
command = 'git',
19+
args = args,
20+
on_exit = function(_, exit_code)
21+
if exit_code > 0 then
22+
callback({})
23+
end
24+
end,
25+
on_stdout = function(_, data)
26+
local ignored_file_paths = {}
27+
for line in data:gmatch('([^\n]+)') do
28+
table.insert(ignored_file_paths, line)
29+
end
30+
31+
callback(ignored_file_paths)
32+
end,
33+
}):start()
34+
end
35+
36+
return M

lua/bufignore/init.lua

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
local config = require('bufignore.config')
2+
local dispatcher = require('bufignore.dispatcher')
3+
4+
--- @class Init
5+
local M = {}
6+
7+
--- Sets up the plugin.
8+
--- @param overrides? UserConfig Configration which will override the defaults.
9+
M.setup = function(overrides)
10+
local user_config = config.setup(overrides)
11+
12+
if user_config.auto_start then
13+
M.start()
14+
end
15+
end
16+
17+
--- Starts the plugin.
18+
M.start = function()
19+
dispatcher.bind_events()
20+
end
21+
22+
--- Stops the plugin.
23+
M.stop = function()
24+
dispatcher.unbind_events()
25+
end
26+
27+
return M

0 commit comments

Comments
 (0)