2023-03-30 09:41:50 +08:00
|
|
|
local event = require('cmp.utils.event')
|
|
|
|
local autocmd = require('cmp.utils.autocmd')
|
|
|
|
local feedkeys = require('cmp.utils.feedkeys')
|
|
|
|
local window = require('cmp.utils.window')
|
|
|
|
local config = require('cmp.config')
|
|
|
|
local types = require('cmp.types')
|
|
|
|
local keymap = require('cmp.utils.keymap')
|
|
|
|
local misc = require('cmp.utils.misc')
|
|
|
|
local api = require('cmp.utils.api')
|
|
|
|
|
|
|
|
local DEFAULT_HEIGHT = 10 -- @see https://github.com/vim/vim/blob/master/src/popupmenu.c#L45
|
|
|
|
|
|
|
|
---@class cmp.CustomEntriesView
|
|
|
|
---@field private entries_win cmp.Window
|
2023-06-08 21:15:37 +08:00
|
|
|
---@field private offset integer
|
2023-03-30 09:41:50 +08:00
|
|
|
---@field private active boolean
|
|
|
|
---@field private entries cmp.Entry[]
|
|
|
|
---@field private column_width any
|
|
|
|
---@field public event cmp.Event
|
|
|
|
local custom_entries_view = {}
|
|
|
|
|
|
|
|
custom_entries_view.ns = vim.api.nvim_create_namespace('cmp.view.custom_entries_view')
|
|
|
|
|
|
|
|
custom_entries_view.new = function()
|
|
|
|
local self = setmetatable({}, { __index = custom_entries_view })
|
2023-06-08 21:15:37 +08:00
|
|
|
|
2023-03-30 09:41:50 +08:00
|
|
|
self.entries_win = window.new()
|
|
|
|
self.entries_win:option('conceallevel', 2)
|
|
|
|
self.entries_win:option('concealcursor', 'n')
|
|
|
|
self.entries_win:option('cursorlineopt', 'line')
|
|
|
|
self.entries_win:option('foldenable', false)
|
|
|
|
self.entries_win:option('wrap', false)
|
|
|
|
-- This is done so that strdisplaywidth calculations for lines in the
|
|
|
|
-- custom_entries_view window exactly match with what is really displayed,
|
|
|
|
-- see comment in cmp.Entry.get_view. Setting tabstop to 1 makes all tabs be
|
|
|
|
-- always rendered one column wide, which removes the unpredictability coming
|
|
|
|
-- from variable width of the tab character.
|
|
|
|
self.entries_win:buffer_option('tabstop', 1)
|
2023-06-08 21:15:37 +08:00
|
|
|
self.entries_win:buffer_option('filetype', 'cmp_menu')
|
|
|
|
self.entries_win:buffer_option('buftype', 'nofile')
|
2023-03-30 09:41:50 +08:00
|
|
|
self.event = event.new()
|
|
|
|
self.offset = -1
|
|
|
|
self.active = false
|
|
|
|
self.entries = {}
|
|
|
|
self.bottom_up = false
|
|
|
|
|
|
|
|
autocmd.subscribe(
|
|
|
|
'CompleteChanged',
|
|
|
|
vim.schedule_wrap(function()
|
|
|
|
if self:visible() and vim.fn.pumvisible() == 1 then
|
|
|
|
self:close()
|
|
|
|
end
|
|
|
|
end)
|
|
|
|
)
|
|
|
|
|
|
|
|
vim.api.nvim_set_decoration_provider(custom_entries_view.ns, {
|
|
|
|
on_win = function(_, win, buf, top, bot)
|
|
|
|
if win ~= self.entries_win.win or buf ~= self.entries_win:get_buffer() then
|
|
|
|
return
|
|
|
|
end
|
|
|
|
|
|
|
|
local fields = config.get().formatting.fields
|
|
|
|
for i = top, bot do
|
|
|
|
local e = self.entries[i + 1]
|
|
|
|
if e then
|
|
|
|
local v = e:get_view(self.offset, buf)
|
2023-06-08 21:15:37 +08:00
|
|
|
local o = config.get().window.completion.side_padding
|
2023-03-30 09:41:50 +08:00
|
|
|
local a = 0
|
|
|
|
for _, field in ipairs(fields) do
|
|
|
|
if field == types.cmp.ItemField.Abbr then
|
|
|
|
a = o
|
|
|
|
end
|
|
|
|
vim.api.nvim_buf_set_extmark(buf, custom_entries_view.ns, i, o, {
|
|
|
|
end_line = i,
|
|
|
|
end_col = o + v[field].bytes,
|
|
|
|
hl_group = v[field].hl_group,
|
|
|
|
hl_mode = 'combine',
|
|
|
|
ephemeral = true,
|
|
|
|
})
|
|
|
|
o = o + v[field].bytes + (self.column_width[field] - v[field].width) + 1
|
|
|
|
end
|
|
|
|
|
|
|
|
for _, m in ipairs(e.matches or {}) do
|
|
|
|
vim.api.nvim_buf_set_extmark(buf, custom_entries_view.ns, i, a + m.word_match_start - 1, {
|
|
|
|
end_line = i,
|
|
|
|
end_col = a + m.word_match_end,
|
|
|
|
hl_group = m.fuzzy and 'CmpItemAbbrMatchFuzzy' or 'CmpItemAbbrMatch',
|
|
|
|
hl_mode = 'combine',
|
|
|
|
ephemeral = true,
|
|
|
|
})
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end,
|
|
|
|
})
|
|
|
|
|
|
|
|
return self
|
|
|
|
end
|
|
|
|
|
|
|
|
custom_entries_view.ready = function()
|
|
|
|
return vim.fn.pumvisible() == 0
|
|
|
|
end
|
|
|
|
|
|
|
|
custom_entries_view.on_change = function(self)
|
|
|
|
self.active = false
|
|
|
|
end
|
|
|
|
|
|
|
|
custom_entries_view.is_direction_top_down = function(self)
|
|
|
|
local c = config.get()
|
|
|
|
if (c.view and c.view.entries and c.view.entries.selection_order) == 'top_down' then
|
|
|
|
return true
|
|
|
|
elseif c.view.entries == nil or c.view.entries.selection_order == nil then
|
|
|
|
return true
|
|
|
|
else
|
|
|
|
return not self.bottom_up
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
custom_entries_view.open = function(self, offset, entries)
|
2023-06-08 21:15:37 +08:00
|
|
|
local completion = config.get().window.completion
|
2023-03-30 09:41:50 +08:00
|
|
|
self.offset = offset
|
|
|
|
self.entries = {}
|
|
|
|
self.column_width = { abbr = 0, kind = 0, menu = 0 }
|
|
|
|
|
|
|
|
local entries_buf = self.entries_win:get_buffer()
|
|
|
|
local lines = {}
|
|
|
|
local dedup = {}
|
2023-06-08 21:15:37 +08:00
|
|
|
local preselect_index = 0
|
2023-03-30 09:41:50 +08:00
|
|
|
for _, e in ipairs(entries) do
|
|
|
|
local view = e:get_view(offset, entries_buf)
|
|
|
|
if view.dup == 1 or not dedup[e.completion_item.label] then
|
|
|
|
dedup[e.completion_item.label] = true
|
|
|
|
self.column_width.abbr = math.max(self.column_width.abbr, view.abbr.width)
|
|
|
|
self.column_width.kind = math.max(self.column_width.kind, view.kind.width)
|
|
|
|
self.column_width.menu = math.max(self.column_width.menu, view.menu.width)
|
|
|
|
table.insert(self.entries, e)
|
|
|
|
table.insert(lines, ' ')
|
2023-06-08 21:15:37 +08:00
|
|
|
if preselect_index == 0 and e.completion_item.preselect then
|
|
|
|
preselect_index = #self.entries
|
2023-03-30 09:41:50 +08:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
vim.api.nvim_buf_set_lines(entries_buf, 0, -1, false, lines)
|
|
|
|
vim.api.nvim_buf_set_option(entries_buf, 'modified', false)
|
|
|
|
|
|
|
|
local width = 0
|
|
|
|
width = width + 1
|
|
|
|
width = width + self.column_width.abbr + (self.column_width.kind > 0 and 1 or 0)
|
|
|
|
width = width + self.column_width.kind + (self.column_width.menu > 0 and 1 or 0)
|
|
|
|
width = width + self.column_width.menu + 1
|
|
|
|
|
|
|
|
local height = vim.api.nvim_get_option('pumheight')
|
|
|
|
height = height ~= 0 and height or #self.entries
|
|
|
|
height = math.min(height, #self.entries)
|
|
|
|
|
|
|
|
local pos = api.get_screen_cursor()
|
2023-06-08 21:15:37 +08:00
|
|
|
local cursor_before_line = api.get_cursor_before_line()
|
|
|
|
local delta = vim.fn.strdisplaywidth(cursor_before_line:sub(self.offset))
|
2023-03-30 09:41:50 +08:00
|
|
|
local row, col = pos[1], pos[2] - delta - 1
|
|
|
|
|
2023-06-08 21:15:37 +08:00
|
|
|
local border_info = window.get_border_info({ style = completion })
|
|
|
|
local border_offset_row = border_info.top + border_info.bottom
|
|
|
|
local border_offset_col = border_info.left + border_info.right
|
|
|
|
if math.floor(vim.o.lines * 0.5) <= row + border_offset_row and vim.o.lines - row - border_offset_row <= math.min(DEFAULT_HEIGHT, height) then
|
2023-03-30 09:41:50 +08:00
|
|
|
height = math.min(height, row - 1)
|
2023-06-08 21:15:37 +08:00
|
|
|
row = row - height - border_offset_row - 1
|
|
|
|
if row < 0 then
|
|
|
|
height = height + row
|
|
|
|
end
|
2023-03-30 09:41:50 +08:00
|
|
|
end
|
2023-06-08 21:15:37 +08:00
|
|
|
if math.floor(vim.o.columns * 0.5) <= col + border_offset_col and vim.o.columns - col - border_offset_col <= width then
|
2023-03-30 09:41:50 +08:00
|
|
|
width = math.min(width, vim.o.columns - 1)
|
2023-06-08 21:15:37 +08:00
|
|
|
col = vim.o.columns - width - border_offset_col - 1
|
|
|
|
if col < 0 then
|
|
|
|
width = width + col
|
|
|
|
end
|
2023-03-30 09:41:50 +08:00
|
|
|
end
|
|
|
|
|
|
|
|
if pos[1] > row then
|
|
|
|
self.bottom_up = true
|
|
|
|
else
|
|
|
|
self.bottom_up = false
|
|
|
|
end
|
|
|
|
|
|
|
|
if not self:is_direction_top_down() then
|
|
|
|
local n = #self.entries
|
|
|
|
for i = 1, math.floor(n / 2) do
|
|
|
|
self.entries[i], self.entries[n - i + 1] = self.entries[n - i + 1], self.entries[i]
|
|
|
|
end
|
2023-06-08 21:15:37 +08:00
|
|
|
if preselect_index ~= 0 then
|
|
|
|
preselect_index = #self.entries - preselect_index + 1
|
2023-03-30 09:41:50 +08:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2023-06-08 21:15:37 +08:00
|
|
|
-- Apply window options (that might be changed) on the custom completion menu.
|
|
|
|
self.entries_win:option('winblend', vim.o.pumblend)
|
|
|
|
self.entries_win:option('winhighlight', completion.winhighlight)
|
|
|
|
self.entries_win:option('scrolloff', completion.scrolloff)
|
2023-03-30 09:41:50 +08:00
|
|
|
self.entries_win:open({
|
|
|
|
relative = 'editor',
|
|
|
|
style = 'minimal',
|
|
|
|
row = math.max(0, row),
|
2023-06-08 21:15:37 +08:00
|
|
|
col = math.max(0, col + completion.col_offset),
|
2023-03-30 09:41:50 +08:00
|
|
|
width = width,
|
|
|
|
height = height,
|
2023-06-08 21:15:37 +08:00
|
|
|
border = completion.border,
|
|
|
|
zindex = completion.zindex or 1001,
|
2023-03-30 09:41:50 +08:00
|
|
|
})
|
|
|
|
-- always set cursor when starting. It will be adjusted on the call to _select
|
|
|
|
vim.api.nvim_win_set_cursor(self.entries_win.win, { 1, 0 })
|
2023-06-08 21:15:37 +08:00
|
|
|
if preselect_index > 0 and config.get().preselect == types.cmp.PreselectMode.Item then
|
|
|
|
self:_select(preselect_index, { behavior = types.cmp.SelectBehavior.Select, active = false })
|
2023-03-30 09:41:50 +08:00
|
|
|
elseif not string.match(config.get().completion.completeopt, 'noselect') then
|
|
|
|
if self:is_direction_top_down() then
|
2023-06-08 21:15:37 +08:00
|
|
|
self:_select(1, { behavior = types.cmp.SelectBehavior.Select, active = false })
|
2023-03-30 09:41:50 +08:00
|
|
|
else
|
2023-06-08 21:15:37 +08:00
|
|
|
self:_select(#self.entries, { behavior = types.cmp.SelectBehavior.Select, active = false })
|
2023-03-30 09:41:50 +08:00
|
|
|
end
|
|
|
|
else
|
|
|
|
if self:is_direction_top_down() then
|
2023-06-08 21:15:37 +08:00
|
|
|
self:_select(0, { behavior = types.cmp.SelectBehavior.Select, active = false })
|
2023-03-30 09:41:50 +08:00
|
|
|
else
|
2023-06-08 21:15:37 +08:00
|
|
|
self:_select(#self.entries + 1, { behavior = types.cmp.SelectBehavior.Select, active = false })
|
2023-03-30 09:41:50 +08:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
custom_entries_view.close = function(self)
|
|
|
|
self.prefix = nil
|
|
|
|
self.offset = -1
|
|
|
|
self.active = false
|
|
|
|
self.entries = {}
|
|
|
|
self.entries_win:close()
|
|
|
|
self.bottom_up = false
|
|
|
|
end
|
|
|
|
|
|
|
|
custom_entries_view.abort = function(self)
|
|
|
|
if self.prefix then
|
|
|
|
self:_insert(self.prefix)
|
|
|
|
end
|
|
|
|
feedkeys.call('', 'n', function()
|
|
|
|
self:close()
|
|
|
|
end)
|
|
|
|
end
|
|
|
|
|
|
|
|
custom_entries_view.draw = function(self)
|
|
|
|
local info = vim.fn.getwininfo(self.entries_win.win)[1]
|
|
|
|
local topline = info.topline - 1
|
|
|
|
local botline = info.topline + info.height - 1
|
|
|
|
local texts = {}
|
|
|
|
local fields = config.get().formatting.fields
|
|
|
|
local entries_buf = self.entries_win:get_buffer()
|
|
|
|
for i = topline, botline - 1 do
|
|
|
|
local e = self.entries[i + 1]
|
|
|
|
if e then
|
|
|
|
local view = e:get_view(self.offset, entries_buf)
|
|
|
|
local text = {}
|
2023-06-08 21:15:37 +08:00
|
|
|
table.insert(text, string.rep(' ', config.get().window.completion.side_padding))
|
2023-03-30 09:41:50 +08:00
|
|
|
for _, field in ipairs(fields) do
|
|
|
|
table.insert(text, view[field].text)
|
|
|
|
table.insert(text, string.rep(' ', 1 + self.column_width[field] - view[field].width))
|
|
|
|
end
|
2023-06-08 21:15:37 +08:00
|
|
|
table.insert(text, string.rep(' ', config.get().window.completion.side_padding))
|
2023-03-30 09:41:50 +08:00
|
|
|
table.insert(texts, table.concat(text, ''))
|
|
|
|
end
|
|
|
|
end
|
|
|
|
vim.api.nvim_buf_set_lines(entries_buf, topline, botline, false, texts)
|
|
|
|
vim.api.nvim_buf_set_option(entries_buf, 'modified', false)
|
|
|
|
|
|
|
|
if api.is_cmdline_mode() then
|
|
|
|
vim.api.nvim_win_call(self.entries_win.win, function()
|
|
|
|
misc.redraw()
|
|
|
|
end)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
custom_entries_view.visible = function(self)
|
|
|
|
return self.entries_win:visible()
|
|
|
|
end
|
|
|
|
|
|
|
|
custom_entries_view.info = function(self)
|
|
|
|
return self.entries_win:info()
|
|
|
|
end
|
|
|
|
|
|
|
|
custom_entries_view.select_next_item = function(self, option)
|
|
|
|
if self:visible() then
|
|
|
|
local cursor = vim.api.nvim_win_get_cursor(self.entries_win.win)[1]
|
2023-06-08 21:15:37 +08:00
|
|
|
local is_top_down = self:is_direction_top_down()
|
|
|
|
local last = #self.entries
|
|
|
|
|
2023-03-30 09:41:50 +08:00
|
|
|
if not self.entries_win:option('cursorline') then
|
2023-06-08 21:15:37 +08:00
|
|
|
cursor = (is_top_down and 1) or last
|
|
|
|
else
|
|
|
|
if is_top_down then
|
|
|
|
if cursor == last then
|
|
|
|
cursor = 0
|
|
|
|
else
|
|
|
|
cursor = cursor + option.count
|
|
|
|
if last < cursor then
|
|
|
|
cursor = last
|
|
|
|
end
|
|
|
|
end
|
|
|
|
else
|
|
|
|
if cursor == 0 then
|
|
|
|
cursor = last
|
|
|
|
else
|
|
|
|
cursor = cursor - option.count
|
|
|
|
if cursor < 0 then
|
|
|
|
cursor = 0
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2023-03-30 09:41:50 +08:00
|
|
|
end
|
2023-06-08 21:15:37 +08:00
|
|
|
|
|
|
|
self:_select(cursor, {
|
|
|
|
behavior = option.behavior or types.cmp.SelectBehavior.Insert,
|
|
|
|
active = true,
|
|
|
|
})
|
2023-03-30 09:41:50 +08:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
custom_entries_view.select_prev_item = function(self, option)
|
|
|
|
if self:visible() then
|
|
|
|
local cursor = vim.api.nvim_win_get_cursor(self.entries_win.win)[1]
|
2023-06-08 21:15:37 +08:00
|
|
|
local is_top_down = self:is_direction_top_down()
|
|
|
|
local last = #self.entries
|
|
|
|
|
2023-03-30 09:41:50 +08:00
|
|
|
if not self.entries_win:option('cursorline') then
|
2023-06-08 21:15:37 +08:00
|
|
|
cursor = (is_top_down and last) or 1
|
|
|
|
else
|
|
|
|
if is_top_down then
|
|
|
|
if cursor == 1 then
|
|
|
|
cursor = 0
|
|
|
|
else
|
|
|
|
cursor = cursor - option.count
|
|
|
|
if cursor < 0 then
|
|
|
|
cursor = 1
|
|
|
|
end
|
|
|
|
end
|
|
|
|
else
|
|
|
|
if cursor == last then
|
|
|
|
cursor = 0
|
|
|
|
else
|
|
|
|
cursor = cursor + option.count
|
|
|
|
if last < cursor then
|
|
|
|
cursor = last
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2023-03-30 09:41:50 +08:00
|
|
|
end
|
2023-06-08 21:15:37 +08:00
|
|
|
|
|
|
|
self:_select(cursor, {
|
|
|
|
behavior = option.behavior or types.cmp.SelectBehavior.Insert,
|
|
|
|
active = true,
|
|
|
|
})
|
2023-03-30 09:41:50 +08:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
custom_entries_view.get_offset = function(self)
|
|
|
|
if self:visible() then
|
|
|
|
return self.offset
|
|
|
|
end
|
|
|
|
return nil
|
|
|
|
end
|
|
|
|
|
|
|
|
custom_entries_view.get_entries = function(self)
|
|
|
|
if self:visible() then
|
|
|
|
return self.entries
|
|
|
|
end
|
|
|
|
return {}
|
|
|
|
end
|
|
|
|
|
|
|
|
custom_entries_view.get_first_entry = function(self)
|
|
|
|
if self:visible() then
|
|
|
|
return (self:is_direction_top_down() and self.entries[1]) or self.entries[#self.entries]
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
custom_entries_view.get_selected_entry = function(self)
|
|
|
|
if self:visible() and self.entries_win:option('cursorline') then
|
|
|
|
return self.entries[vim.api.nvim_win_get_cursor(self.entries_win.win)[1]]
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
custom_entries_view.get_active_entry = function(self)
|
|
|
|
if self:visible() and self.active then
|
|
|
|
return self:get_selected_entry()
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
custom_entries_view._select = function(self, cursor, option)
|
|
|
|
local is_insert = (option.behavior or types.cmp.SelectBehavior.Insert) == types.cmp.SelectBehavior.Insert
|
|
|
|
if is_insert and not self.active then
|
|
|
|
self.prefix = string.sub(api.get_current_line(), self.offset, api.get_cursor()[2]) or ''
|
|
|
|
end
|
2023-06-08 21:15:37 +08:00
|
|
|
self.active = (0 < cursor and cursor <= #self.entries and option.active == true)
|
2023-03-30 09:41:50 +08:00
|
|
|
|
|
|
|
self.entries_win:option('cursorline', cursor > 0 and cursor <= #self.entries)
|
|
|
|
vim.api.nvim_win_set_cursor(self.entries_win.win, {
|
|
|
|
math.max(math.min(cursor, #self.entries), 1),
|
|
|
|
0,
|
|
|
|
})
|
|
|
|
|
|
|
|
if is_insert then
|
|
|
|
self:_insert(self.entries[cursor] and self.entries[cursor]:get_vim_item(self.offset).word or self.prefix)
|
|
|
|
end
|
|
|
|
|
|
|
|
self.entries_win:update()
|
|
|
|
self:draw()
|
|
|
|
self.event:emit('change')
|
|
|
|
end
|
|
|
|
|
|
|
|
custom_entries_view._insert = setmetatable({
|
|
|
|
pending = false,
|
|
|
|
}, {
|
|
|
|
__call = function(this, self, word)
|
|
|
|
word = word or ''
|
|
|
|
if api.is_cmdline_mode() then
|
|
|
|
local cursor = api.get_cursor()
|
2023-06-08 21:15:37 +08:00
|
|
|
-- setcmdline() added in v0.8.0
|
|
|
|
if vim.fn.has('nvim-0.8') == 1 then
|
|
|
|
local current_line = api.get_current_line()
|
|
|
|
local before_line = current_line:sub(1, self.offset - 1)
|
|
|
|
local after_line = current_line:sub(cursor[2] + 1)
|
|
|
|
local pos = #before_line + #word + 1
|
|
|
|
vim.fn.setcmdline(before_line .. word .. after_line, pos)
|
|
|
|
vim.api.nvim_feedkeys(keymap.t('<Cmd>redraw<CR>'), 'ni', false)
|
|
|
|
else
|
|
|
|
vim.api.nvim_feedkeys(keymap.backspace(string.sub(api.get_current_line(), self.offset, cursor[2])) .. word, 'int', true)
|
|
|
|
end
|
2023-03-30 09:41:50 +08:00
|
|
|
else
|
|
|
|
if this.pending then
|
|
|
|
return
|
|
|
|
end
|
|
|
|
this.pending = true
|
|
|
|
|
|
|
|
local release = require('cmp').suspend()
|
|
|
|
feedkeys.call('', '', function()
|
|
|
|
local cursor = api.get_cursor()
|
|
|
|
local keys = {}
|
|
|
|
table.insert(keys, keymap.indentkeys())
|
|
|
|
table.insert(keys, keymap.backspace(string.sub(api.get_current_line(), self.offset, cursor[2])))
|
|
|
|
table.insert(keys, word)
|
|
|
|
table.insert(keys, keymap.indentkeys(vim.bo.indentkeys))
|
|
|
|
feedkeys.call(
|
|
|
|
table.concat(keys, ''),
|
|
|
|
'int',
|
|
|
|
vim.schedule_wrap(function()
|
|
|
|
this.pending = false
|
|
|
|
release()
|
|
|
|
end)
|
|
|
|
)
|
|
|
|
end)
|
|
|
|
end
|
|
|
|
end,
|
|
|
|
})
|
|
|
|
|
|
|
|
return custom_entries_view
|