-
Notifications
You must be signed in to change notification settings - Fork 11
/
buffer_list.lua
203 lines (177 loc) · 6.59 KB
/
buffer_list.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
-- Copyright 2011-2012 Nils Nordman <nino at nordman.org>
-- Copyright 2012-2014 Robert Gieseke <[email protected]>
-- License: MIT (see LICENSE)
--[[--
The buffer list module provides a text based replacement for the standard
Textadept buffer list.
## Usage
Use the @{textredux.hijack} function or load the buffer list
in your `~/.textadept/init.lua`:
local textredux = require('textredux')
keys["ctrl+b"] = textredux.buffer_list.show
## Features
- Close a buffer from the buffer list (bound to `Ctrl + D` by default)
- Close all files currently shown in the buffer list.
(bound to `Ctrl + Shift + D` and `Meta + D` in Curses by default)
- The list of buffers is sorted and the current buffer is pre-selected
- The buffers to show can be specified using a function
@module textredux.buffer_list
]]
local reduxlist = require 'textredux.core.list'
local M = {}
--- The Textredux list instance used by the buffer list.
M.list = nil
--[[-- The key bindings for the buffer list.
You can modifiy this to customise the key bindings to your liking. The key
bindings are passed directly to the Textredux list, so note that the
first argument to any function will be the Textredux list itself.
You can read more about the Textredux list's keys in the
[list documentation](./textredux.core.list.html#keys).
If you like to add a custom key binding for closing a buffer or all buffers
in the current selection you can bind the @{close_buffer} and @{close_selected}
functions to a key of your choice. For other actions it's likely that you want to
obtain the currently selected buffer - you can use the @{currently_selected_buffer}
function for that.
]]
M.keys = {
["ctrl+d"] = function(list) M.close_buffer(list) end, -- Default for `close buffer`
[CURSES and 'meta+d' or 'ctrl+D'] = function(list) M.close_selected(list) end,
}
local buffer_source
local function shorten_home_dir(directory)
if not directory then return end
local home_dir = os.getenv('HOME') or os.getenv('UserProfile')
return directory:gsub(home_dir, '~')
end
local function buffer_title(buffer)
local title = (buffer.filename or ''):match('[\\/]([^/\\]+)$')
return title or buffer.filename or buffer._type or _L['Untitled']
end
local function buffer_directory(buffer)
if not buffer.filename then return nil end
return shorten_home_dir(buffer.filename:match('^(.+[\\/])[^/\\]+$'))
end
local function get_buffer_items()
local items = {}
for _, buffer in ipairs(buffer_source()) do
if M.list.buffer.target ~= buffer then
local modified = buffer.modify and '*' or ''
items[#items + 1] = {
buffer_title(buffer) .. modified,
buffer_directory(buffer),
buffer = buffer
}
end
end
table.sort(items, function(a, b)
if a[2] == b[2] then return a[1] < b[1] end
if a[2] and b[2] then return a[2] < b[2] end
return a[1] < b[1]
end)
return items
end
local function on_selection(list, item)
list:close()
local target = item.buffer
if buffer ~= target then view:goto_buffer(target) end
end
--[[-- Returns the currently selected buffer in the list.
@param list The Textredux list instance used by the buffer list. If not
provided, then the global list is used automatically.
@return The currently selected buffer, if any.
@return The currently selected buffer's name, if any.
]]
function M.currently_selected_buffer(list)
list = list or M.list
if not list then error('`list` must be provided', 2) end
local item = list:get_current_selection()
if item then return item.buffer, item[1] end
end
--[[-- Closes the currently selected buffer in the buffer list.
@param list The Textredux list instance used by the buffer list. This function
is ordinarily invoked as the result of a key binding, and you should thus not
need to specify this yourself. If list isn't provided, the global list is
automatically used.
]]
function M.close_buffer(list)
list = list or M.list
if not list then error('`list` must be provided', 2) end
local sel_buffer, name = M.currently_selected_buffer(list)
if sel_buffer then
ui.statusbar_text = 'Closing ' .. name .. '..'
local current_pos = buffer.current_pos
local current_search = list:get_current_search()
view:goto_buffer(sel_buffer)
local closed = sel_buffer:close()
list.items = get_buffer_items()
list:show()
if closed then
list:set_current_search(current_search)
buffer.goto_pos(math.min(current_pos, buffer.length + 1))
buffer.home()
ui.statusbar_text = 'Closed ' .. name
else
ui.statusbar_text = ''
end
end
end
--[[-- Closes all currently selected/filtered files in the buffer list.
@param list The Textredux list instance used by the buffer list. This function
is ordinarily invoked as the result of a key binding, and you should thus not
need to specify this yourself. If list isn't provided, the global list is
automatically used.
]]
function M.close_selected(list)
list = list or M.list
if not list then error('`list` must be provided', 2) end
local current_search = list:get_current_search()
if not current_search then return end
while true do
local sel_buffer, _ = M.currently_selected_buffer(list)
if not sel_buffer then break end
local current_pos = buffer.current_pos
view:goto_buffer(sel_buffer)
local closed = sel_buffer:close()
list.items = get_buffer_items()
list:show()
if closed then
list:set_current_search(current_search)
buffer.goto_pos(math.min(current_pos, buffer.length + 1))
buffer.home()
end
end
list:set_current_search('')
ui.statusbar_text = 'All selected buffers closed'
end
--- Shows a list of the specified buffers, or _G.BUFFERS if not specified.
-- @param buffers Either nil, in which case all buffers within _G.BUFFERS
-- are displayed, or a function returning a table of buffers to display.
function M.show(buffers)
buffer_source = buffers or function() return _BUFFERS end
if not M.list then
M.list = reduxlist.new('Buffer list')
M.list.headers = {'Name', 'Directory'}
M.list.on_selection = on_selection
for k, v in pairs(M.keys) do
M.list.keys[k] = v
end
end
M.list.items = get_buffer_items()
local buffer = buffer
local active_buffer
for index, item in ipairs(M.list.items) do
if item.buffer == buffer then
active_buffer = index
break
end
end
M.list:show()
if active_buffer then
local line = M.list.buffer.data.items_start_line + active_buffer
M.list.buffer:goto_line(line - 1)
end
local short_cut = CURSES and '[Meta+D]' or '[Ctrl+Shift+D]'
ui.statusbar_text = '[Enter] = open, [Ctrl+D] = close selected, '..
short_cut..' = close all buffers in current list'
end
return M