Added and updated many plugins
This commit is contained in:
parent
782a7acc21
commit
0ebc0e789d
|
@ -70,6 +70,10 @@ need.
|
||||||
|
|
||||||
The included plugins are the following:
|
The included plugins are the following:
|
||||||
|
|
||||||
|
**amimodkeys**
|
||||||
|
This plugin enables the Right Amiga and Right Alt to behave like Control,
|
||||||
|
for those that are used to use them.
|
||||||
|
|
||||||
**autoinsert**
|
**autoinsert**
|
||||||
Automatically inserts closing brackets and quotes. Also allows selected
|
Automatically inserts closing brackets and quotes. Also allows selected
|
||||||
text to be wrapped with brackets or quotes.
|
text to be wrapped with brackets or quotes.
|
||||||
|
@ -124,6 +128,9 @@ folder like below:
|
||||||
**indentguide**
|
**indentguide**
|
||||||
Adds indent guides
|
Adds indent guides
|
||||||
|
|
||||||
|
**keyhud**
|
||||||
|
Simple key HUD display for lite-xl.
|
||||||
|
|
||||||
**language_guide**
|
**language_guide**
|
||||||
Syntax for the AmigaGuide scripting language
|
Syntax for the AmigaGuide scripting language
|
||||||
|
|
||||||
|
@ -142,6 +149,9 @@ Automatically inserts indentation and closing bracket/text after newline
|
||||||
**markers**
|
**markers**
|
||||||
Add markers to docs and jump between them quickly
|
Add markers to docs and jump between them quickly
|
||||||
|
|
||||||
|
**memoryusage**
|
||||||
|
Show memory usage in the status view
|
||||||
|
|
||||||
**minimap**
|
**minimap**
|
||||||
Shows a minimap on the right-hand side of the docview. Please note that
|
Shows a minimap on the right-hand side of the docview. Please note that
|
||||||
this plugin will make the editor slower on file loading and scrolling.
|
this plugin will make the editor slower on file loading and scrolling.
|
||||||
|
@ -178,9 +188,19 @@ Highlights regions of code that match the current selection
|
||||||
**smallclock**
|
**smallclock**
|
||||||
It adds a small clock at the bottom right corner.
|
It adds a small clock at the bottom right corner.
|
||||||
|
|
||||||
|
**sort**
|
||||||
|
Sorts selected lines alphabetically
|
||||||
|
|
||||||
|
**sortcss**
|
||||||
|
Sort selected CSS properties alphabetically or using the concentric model.
|
||||||
|
|
||||||
**tetris**
|
**tetris**
|
||||||
Play Tetris inside Lite XL.
|
Play Tetris inside Lite XL.
|
||||||
|
|
||||||
|
**todotreeview**
|
||||||
|
Todo tree viewer for annotations in code like TODO, BUG, FIX,
|
||||||
|
IMPROVEMENT
|
||||||
|
|
||||||
## Tips and tricks
|
## Tips and tricks
|
||||||
### Transitions
|
### Transitions
|
||||||
|
|
||||||
|
@ -231,12 +251,21 @@ https://git.walkero.gr/walkero/lite-xl/issues
|
||||||
# Changelog
|
# Changelog
|
||||||
## [2.1.7r1] - 2024-12-26
|
## [2.1.7r1] - 2024-12-26
|
||||||
### Added
|
### Added
|
||||||
- Added widget library
|
- Added the widget library
|
||||||
- Added settings plugin that shows a GUI for chnaging the app settings
|
- Added the settings plugin that shows a GUI for chnaging the app settings
|
||||||
- Added search_ui plugin that adds a GUI for search
|
- Added the search_ui plugin that adds a GUI for search
|
||||||
|
- Added the amimodkeys plugin that the Right Amiga and Right Alt to behave
|
||||||
|
like Control
|
||||||
|
- Added the memoryusage plugin
|
||||||
|
- Added the todotreeview plugin
|
||||||
|
- Added the keyhud plugin
|
||||||
|
- Added the sort plugin
|
||||||
|
- Added the sortcss plugin
|
||||||
|
|
||||||
### Updated
|
### Updated
|
||||||
- Updated the code to the upstream 2.1.7 release
|
- Updated the code to the upstream 2.1.7 release
|
||||||
|
- Updated the minimap plugin
|
||||||
|
- Updated the indentguide plugin
|
||||||
|
|
||||||
## [2.1.6r1] - 2024-12-3
|
## [2.1.6r1] - 2024-12-3
|
||||||
### Changed
|
### Changed
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
-- mod-version:3
|
||||||
|
local keymap = require "core.keymap"
|
||||||
|
|
||||||
|
local on_key_pressed = keymap.on_key_pressed
|
||||||
|
local on_key_released = keymap.on_key_released
|
||||||
|
|
||||||
|
local function remap_key(k)
|
||||||
|
return k:gsub("right alt", "control")
|
||||||
|
:gsub("right amiga", "control")
|
||||||
|
end
|
||||||
|
|
||||||
|
function keymap.on_key_pressed(k, ...)
|
||||||
|
return on_key_pressed(remap_key(k), ...)
|
||||||
|
end
|
||||||
|
|
||||||
|
function keymap.on_key_released(k, ...)
|
||||||
|
return on_key_released(remap_key(k), ...)
|
||||||
|
end
|
||||||
|
|
|
@ -6,6 +6,7 @@ local DocView = require "core.docview"
|
||||||
|
|
||||||
config.plugins.indentguide = common.merge({
|
config.plugins.indentguide = common.merge({
|
||||||
enabled = true,
|
enabled = true,
|
||||||
|
highlight = true,
|
||||||
-- The config specification used by the settings gui
|
-- The config specification used by the settings gui
|
||||||
config_spec = {
|
config_spec = {
|
||||||
name = "Indent Guide",
|
name = "Indent Guide",
|
||||||
|
@ -15,28 +16,28 @@ config.plugins.indentguide = common.merge({
|
||||||
path = "enabled",
|
path = "enabled",
|
||||||
type = "toggle",
|
type = "toggle",
|
||||||
default = true
|
default = true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label = "Highlight Line",
|
||||||
|
description = "Toggle the highlight of the curent indentation indicator lines.",
|
||||||
|
path = "highlight",
|
||||||
|
type = "toggle",
|
||||||
|
default = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, config.plugins.indentguide)
|
}, config.plugins.indentguide)
|
||||||
|
|
||||||
-- TODO: replace with `doc:get_indent_info()` when 2.1 releases
|
local indentguide = {}
|
||||||
local function get_indent_info(doc)
|
|
||||||
if doc.get_indent_info then
|
|
||||||
return doc:get_indent_info()
|
|
||||||
end
|
|
||||||
return config.tab_type, config.indent_size
|
|
||||||
end
|
|
||||||
|
|
||||||
|
function indentguide.get_line_spaces(doc, line, dir)
|
||||||
local function get_line_spaces(doc, line, dir)
|
local _, indent_size = doc:get_indent_info()
|
||||||
local _, indent_size = get_indent_info(doc)
|
|
||||||
local text = doc.lines[line]
|
local text = doc.lines[line]
|
||||||
if not text or #text == 1 then
|
if not text or #text == 1 then
|
||||||
return -1
|
return -1
|
||||||
end
|
end
|
||||||
local s, e = text:find("^%s*")
|
local s, e = text:find("^%s*")
|
||||||
if e == #text then
|
if e == #text then
|
||||||
return get_line_spaces(doc, line + dir, dir)
|
return indentguide.get_line_spaces(doc, line + dir, dir)
|
||||||
end
|
end
|
||||||
local n = 0
|
local n = 0
|
||||||
for _,b in pairs({text:byte(s, e)}) do
|
for _,b in pairs({text:byte(s, e)}) do
|
||||||
|
@ -46,15 +47,16 @@ local function get_line_spaces(doc, line, dir)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
local function get_line_indent_guide_spaces(doc, line)
|
function indentguide.get_line_indent_guide_spaces(doc, line)
|
||||||
if doc.lines[line]:find("^%s*\n") then
|
if doc.lines[line]:find("^%s*\n") then
|
||||||
return math.max(
|
return math.max(
|
||||||
get_line_spaces(doc, line - 1, -1),
|
indentguide.get_line_spaces(doc, line - 1, -1),
|
||||||
get_line_spaces(doc, line + 1, 1))
|
indentguide.get_line_spaces(doc, line + 1, 1))
|
||||||
end
|
end
|
||||||
return get_line_spaces(doc, line)
|
return indentguide.get_line_spaces(doc, line)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
local docview_update = DocView.update
|
local docview_update = DocView.update
|
||||||
function DocView:update()
|
function DocView:update()
|
||||||
docview_update(self)
|
docview_update(self)
|
||||||
|
@ -66,7 +68,7 @@ function DocView:update()
|
||||||
local function get_indent(line)
|
local function get_indent(line)
|
||||||
if line < 1 or line > #self.doc.lines then return -1 end
|
if line < 1 or line > #self.doc.lines then return -1 end
|
||||||
if not self.indentguide_indents[line] then
|
if not self.indentguide_indents[line] then
|
||||||
self.indentguide_indents[line] = get_line_indent_guide_spaces(self.doc, line)
|
self.indentguide_indents[line] = indentguide.get_line_indent_guide_spaces(self.doc, line)
|
||||||
end
|
end
|
||||||
return self.indentguide_indents[line]
|
return self.indentguide_indents[line]
|
||||||
end
|
end
|
||||||
|
@ -76,10 +78,10 @@ function DocView:update()
|
||||||
|
|
||||||
local minline, maxline = self:get_visible_line_range()
|
local minline, maxline = self:get_visible_line_range()
|
||||||
for i = minline, maxline do
|
for i = minline, maxline do
|
||||||
self.indentguide_indents[i] = get_line_indent_guide_spaces(self.doc, i)
|
self.indentguide_indents[i] = indentguide.get_line_indent_guide_spaces(self.doc, i)
|
||||||
end
|
end
|
||||||
|
|
||||||
local _, indent_size = get_indent_info(self.doc)
|
local _, indent_size = self.doc:get_indent_info()
|
||||||
for _,line in self.doc:get_selections() do
|
for _,line in self.doc:get_selections() do
|
||||||
local lvl = get_indent(line)
|
local lvl = get_indent(line)
|
||||||
local top, bottom
|
local top, bottom
|
||||||
|
@ -121,19 +123,26 @@ function DocView:update()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function indentguide.get_width()
|
||||||
|
return math.max(1, SCALE)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
local draw_line_text = DocView.draw_line_text
|
local draw_line_text = DocView.draw_line_text
|
||||||
function DocView:draw_line_text(line, x, y)
|
function DocView:draw_line_text(line, x, y)
|
||||||
if config.plugins.indentguide.enabled and self:is(DocView) then
|
if config.plugins.indentguide.enabled and self:is(DocView) then
|
||||||
local spaces = self.indentguide_indents[line] or -1
|
local spaces = self.indentguide_indents[line] or -1
|
||||||
local _, indent_size = get_indent_info(self.doc)
|
local _, indent_size = self.doc:get_indent_info()
|
||||||
local w = math.max(1, SCALE)
|
local w = indentguide.get_width()
|
||||||
local h = self:get_line_height()
|
local h = self:get_line_height()
|
||||||
local font = self:get_font()
|
local font = self:get_font()
|
||||||
local space_sz = font:get_width(" ")
|
local space_sz = font:get_width(" ")
|
||||||
for i = 0, spaces - 1, indent_size do
|
for i = 0, spaces - 1, indent_size do
|
||||||
local color = style.guide or style.selection
|
local color = style.guide or style.selection
|
||||||
local active_lvl = self.indentguide_indent_active[line] or -1
|
local active_lvl = self.indentguide_indent_active[line] or -1
|
||||||
if i < active_lvl and i + indent_size >= active_lvl then
|
if i < active_lvl
|
||||||
|
and i + indent_size >= active_lvl
|
||||||
|
and config.plugins.indentguide.highlight then
|
||||||
color = style.guide_highlight or style.accent
|
color = style.guide_highlight or style.accent
|
||||||
end
|
end
|
||||||
local sw = space_sz * i
|
local sw = space_sz * i
|
||||||
|
@ -142,3 +151,5 @@ function DocView:draw_line_text(line, x, y)
|
||||||
end
|
end
|
||||||
return draw_line_text(self, line, x, y)
|
return draw_line_text(self, line, x, y)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
return indentguide
|
||||||
|
|
|
@ -0,0 +1,192 @@
|
||||||
|
-- mod-version:3
|
||||||
|
local core = require "core"
|
||||||
|
local keymap = require "core.keymap"
|
||||||
|
local style = require "core.style"
|
||||||
|
local CommandView = require "core.commandview"
|
||||||
|
local RootView = require "core.rootview"
|
||||||
|
local config = require "core.config"
|
||||||
|
local common = require "core.common"
|
||||||
|
|
||||||
|
|
||||||
|
local keyhud = {}
|
||||||
|
|
||||||
|
config.plugins.keyhud = common.merge({
|
||||||
|
stroke_map = {
|
||||||
|
["escape"] = "<ESC>",
|
||||||
|
["space"] = "<SPACE>", --"␣""
|
||||||
|
["left gui"] = "<CMD>", --"⌘"
|
||||||
|
["right gui"] = "<CMD>",
|
||||||
|
["left ctrl"] = "<CTRL>",
|
||||||
|
["control"] = "<CTRL>",
|
||||||
|
["right ctrl"] = "<CTRL>",
|
||||||
|
["left alt"] = "<ALT>",
|
||||||
|
["right alt"] = "<ALT>",
|
||||||
|
["left amiga"] = "<LAMIGA>",
|
||||||
|
["right amiga"] = "<RAMIGA>",
|
||||||
|
["left"] = "←",
|
||||||
|
["right"] = "→",
|
||||||
|
["up"] = "↑",
|
||||||
|
["down"] = "↓",
|
||||||
|
["left shift"] = "⇧",
|
||||||
|
["right shift"] = "⇧",
|
||||||
|
["capslock"] = "⇪",
|
||||||
|
["return"] = "<RETURN>", --"↵",
|
||||||
|
["backspace"] = "⌫",
|
||||||
|
["delete"] = "⌦",
|
||||||
|
["pageup"] = "<UP>", --"⇞",
|
||||||
|
["pagedown"] = "<DOWN>", --"⇟",
|
||||||
|
["home"] = "<HOME>", --"↖",
|
||||||
|
["end"] = "<END>", --"↘",
|
||||||
|
["tab"] = "<TAB>", --"⇥",
|
||||||
|
},
|
||||||
|
max_time = 0.5,
|
||||||
|
only_mapped = false,
|
||||||
|
filters = {
|
||||||
|
["commandview"] = true,
|
||||||
|
["mouse"] = true
|
||||||
|
},
|
||||||
|
position = "right",
|
||||||
|
}, config.plugins.keyhud)
|
||||||
|
|
||||||
|
style.keyhud = common.merge(
|
||||||
|
{
|
||||||
|
background = { common.color "#00000066" },
|
||||||
|
text = { common.color "#ffffffdd" },
|
||||||
|
font = style.big_font, -- style.code_font:copy(46 * SCALE)
|
||||||
|
},
|
||||||
|
style.keyhud
|
||||||
|
)
|
||||||
|
|
||||||
|
keyhud.last_strokes = {}
|
||||||
|
keyhud.last_strokes_time_stamp = {}
|
||||||
|
|
||||||
|
|
||||||
|
keyhud.on_key_pressed__orig = keymap.on_key_pressed
|
||||||
|
keyhud.on_key_released__orig = keymap.on_key_released
|
||||||
|
|
||||||
|
|
||||||
|
local function dv()
|
||||||
|
return core.active_view
|
||||||
|
end
|
||||||
|
|
||||||
|
function keymap.on_key_pressed(k, ...)
|
||||||
|
if dv():is(CommandView) and config.plugins.keyhud.filters.commandview then
|
||||||
|
return keyhud.on_key_pressed__orig(k, ...)
|
||||||
|
end
|
||||||
|
if config.plugins.keyhud.filters.mouse and (string.find(k, "click", 1, true) or string.find(k, "wheel", 1, true)) then
|
||||||
|
return keyhud.on_key_pressed__orig(k, ...)
|
||||||
|
end
|
||||||
|
local x = config.plugins.keyhud.stroke_map[k]
|
||||||
|
if x == nil and not config.plugins.keyhud.only_mapped then
|
||||||
|
if #k > 1 then
|
||||||
|
x = '<' .. k .. '>'
|
||||||
|
else
|
||||||
|
x = k
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if x ~= nil then
|
||||||
|
for i, key in ipairs(keyhud.last_strokes) do
|
||||||
|
if x == key then
|
||||||
|
keyhud.last_strokes_time_stamp[i] = -1
|
||||||
|
x = nil
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if x ~= nil then
|
||||||
|
table.insert(keyhud.last_strokes, x)
|
||||||
|
table.insert(keyhud.last_strokes_time_stamp, -1)
|
||||||
|
end
|
||||||
|
return keyhud.on_key_pressed__orig(k, ...)
|
||||||
|
end
|
||||||
|
|
||||||
|
function keymap.on_key_released(k)
|
||||||
|
if #keyhud.last_strokes then
|
||||||
|
local x = config.plugins.keyhud.stroke_map[k]
|
||||||
|
if x == nil then
|
||||||
|
x = k
|
||||||
|
end
|
||||||
|
for i, key in ipairs(keyhud.last_strokes) do
|
||||||
|
if x == key then
|
||||||
|
keyhud.last_strokes_time_stamp[i] = system.get_time()
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return keyhud.on_key_released__orig(k)
|
||||||
|
end
|
||||||
|
|
||||||
|
local rvDraw = RootView.draw
|
||||||
|
function RootView:draw(...)
|
||||||
|
rvDraw(self, ...)
|
||||||
|
local position = config.plugins.keyhud.position
|
||||||
|
if position ~= 'right' and position ~= 'left' then
|
||||||
|
core.error("`config.plugins.keyhud.position` can be only `left` or `right`")
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
local font = style.keyhud.font
|
||||||
|
local h = font:get_height() + 20
|
||||||
|
local w = h
|
||||||
|
local y = self.size.y - 10
|
||||||
|
local next_strokes = {}
|
||||||
|
local next_timestamps = {}
|
||||||
|
local start_i, end_i, step = 0, 0, 1
|
||||||
|
if position == "left" then
|
||||||
|
local x = 10
|
||||||
|
for i = 1, #keyhud.last_strokes do
|
||||||
|
local t0 = keyhud.last_strokes_time_stamp[i]
|
||||||
|
if t0 < 0 or system.get_time() - t0 < config.plugins.keyhud.max_time then
|
||||||
|
local key = keyhud.last_strokes[i]
|
||||||
|
core.redraw = true
|
||||||
|
-- y = self.size.y - core.status_view.size.y
|
||||||
|
local tw = font:get_width(key)
|
||||||
|
local th = font:get_height()
|
||||||
|
w = h
|
||||||
|
if tw + 20 > w then
|
||||||
|
w = tw + 20
|
||||||
|
end
|
||||||
|
renderer.draw_rect(x, y - h, w, h, style.keyhud.background)
|
||||||
|
renderer.draw_text(font, key, x + w / 2 - tw / 2, y - h / 2 - th / 2,
|
||||||
|
style.keyhud.text)
|
||||||
|
x = x + w + 10
|
||||||
|
table.insert(next_strokes, key)
|
||||||
|
table.insert(next_timestamps, t0)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
start_i = 1
|
||||||
|
end_i = #next_strokes
|
||||||
|
step = 1
|
||||||
|
else
|
||||||
|
local x = self.size.x - 10
|
||||||
|
for i = #keyhud.last_strokes, 1, -1 do
|
||||||
|
local t0 = keyhud.last_strokes_time_stamp[i]
|
||||||
|
if t0 < 0 or system.get_time() - t0 < config.plugins.keyhud.max_time then
|
||||||
|
local key = keyhud.last_strokes[i]
|
||||||
|
core.redraw = true
|
||||||
|
-- y = self.size.y - core.status_view.size.y
|
||||||
|
local tw = font:get_width(key)
|
||||||
|
local th = font:get_height()
|
||||||
|
if tw + 20 > w then
|
||||||
|
w = tw + 20
|
||||||
|
end
|
||||||
|
renderer.draw_rect(x - w, y - h, w, h, style.keyhud.background)
|
||||||
|
renderer.draw_text(font, key, x - w / 2 - tw / 2, y - h / 2 - th / 2,
|
||||||
|
style.keyhud.text)
|
||||||
|
x = x - w - 10
|
||||||
|
table.insert(next_strokes, key)
|
||||||
|
table.insert(next_timestamps, t0)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
start_i = #next_strokes
|
||||||
|
end_i = 1
|
||||||
|
step = -1
|
||||||
|
end
|
||||||
|
keyhud.last_strokes = {}
|
||||||
|
keyhud.last_strokes_time_stamp = {}
|
||||||
|
for i = start_i, end_i, step do
|
||||||
|
table.insert(keyhud.last_strokes, next_strokes[i])
|
||||||
|
table.insert(keyhud.last_strokes_time_stamp, next_timestamps[i])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return keyhud
|
|
@ -0,0 +1,49 @@
|
||||||
|
-- mod-version:3
|
||||||
|
-- original implementation by AqilCont
|
||||||
|
local core = require "core"
|
||||||
|
local config = require "core.config"
|
||||||
|
local common = require "core.common"
|
||||||
|
local style = require "core.style"
|
||||||
|
local StatusView = require "core.statusview"
|
||||||
|
|
||||||
|
config.plugins.memoryusage = common.merge({
|
||||||
|
enabled = true,
|
||||||
|
-- The config specification used by the settings gui
|
||||||
|
config_spec = {
|
||||||
|
name = "Memory Usage",
|
||||||
|
{
|
||||||
|
label = "Enabled",
|
||||||
|
description = "Show or hide the lua memory usage from the status bar.",
|
||||||
|
path = "enabled",
|
||||||
|
type = "toggle",
|
||||||
|
default = true,
|
||||||
|
on_apply = function(enabled)
|
||||||
|
core.add_thread(function()
|
||||||
|
if enabled then
|
||||||
|
core.status_view:get_item("status:memory-usage"):show()
|
||||||
|
else
|
||||||
|
core.status_view:get_item("status:memory-usage"):hide()
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, config.plugins.memoryusage)
|
||||||
|
|
||||||
|
core.status_view:add_item({
|
||||||
|
name = "status:memory-usage",
|
||||||
|
alignment = StatusView.Item.RIGHT,
|
||||||
|
get_item = function()
|
||||||
|
return {
|
||||||
|
style.text,
|
||||||
|
string.format(
|
||||||
|
"%.2f MB",
|
||||||
|
(math.floor(collectgarbage("count") / 10.24) / 100)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
end,
|
||||||
|
position = 1,
|
||||||
|
tooltip = "lua memory usage",
|
||||||
|
separator = core.status_view.separator2
|
||||||
|
})
|
||||||
|
|
|
@ -135,29 +135,21 @@ config.plugins.minimap = common.merge({
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label = "Selection Color",
|
label = "Selection Color",
|
||||||
description = "Background color of selected text in html notation eg: #FFFFFF. Leave empty to use default.",
|
description = "Background color of selected text.",
|
||||||
path = "selection_color_html",
|
path = "selection_color",
|
||||||
type = "string",
|
type = "color",
|
||||||
on_apply = function(value)
|
default = string.format("#%02X%02X%02X%02X",
|
||||||
if value and value:match("#%x%x%x%x%x%x") then
|
style.dim[1], style.dim[2], style.dim[3], style.dim[4]
|
||||||
config.plugins.minimap.selection_color = { common.color(value) }
|
)
|
||||||
else
|
|
||||||
config.plugins.minimap.selection_color = nil
|
|
||||||
end
|
|
||||||
end
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label = "Caret Color",
|
label = "Caret Color",
|
||||||
description = "Background color of active line in html notation eg: #FFFFFF. Leave empty to use default.",
|
description = "Background color of active line.",
|
||||||
path = "caret_color_html",
|
path = "caret_color",
|
||||||
type = "string",
|
type = "color",
|
||||||
on_apply = function(value)
|
default = string.format("#%02X%02X%02X%02X",
|
||||||
if value and value:match("#%x%x%x%x%x%x") then
|
style.caret[1], style.caret[2], style.caret[3], style.caret[4]
|
||||||
config.plugins.minimap.caret_color = { common.color(value) }
|
)
|
||||||
else
|
|
||||||
config.plugins.minimap.caret_color = nil
|
|
||||||
end
|
|
||||||
end
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label = "Highlight Alignment",
|
label = "Highlight Alignment",
|
||||||
|
@ -236,8 +228,6 @@ local function reset_cache_if_needed()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
-- Move cache to make space for new lines
|
-- Move cache to make space for new lines
|
||||||
local prev_insert_notify = Highlighter.insert_notify
|
local prev_insert_notify = Highlighter.insert_notify
|
||||||
function Highlighter:insert_notify(line, n, ...)
|
function Highlighter:insert_notify(line, n, ...)
|
||||||
|
@ -246,13 +236,11 @@ function Highlighter:insert_notify(line, n, ...)
|
||||||
if not highlighter_cache[self] then
|
if not highlighter_cache[self] then
|
||||||
highlighter_cache[self] = {}
|
highlighter_cache[self] = {}
|
||||||
else
|
else
|
||||||
local to = math.min(line + n, #self.doc.lines)
|
local blanks = { }
|
||||||
for i=#self.doc.lines+n,to,-1 do
|
for i = 1, n do
|
||||||
highlighter_cache[self][i] = highlighter_cache[self][i - n]
|
blanks[i] = false
|
||||||
end
|
|
||||||
for i=line,to do
|
|
||||||
highlighter_cache[self][i] = nil
|
|
||||||
end
|
end
|
||||||
|
common.splice(highlighter_cache[self], line, 0, blanks)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -264,10 +252,7 @@ function Highlighter:remove_notify(line, n, ...)
|
||||||
if not highlighter_cache[self] then
|
if not highlighter_cache[self] then
|
||||||
highlighter_cache[self] = {}
|
highlighter_cache[self] = {}
|
||||||
else
|
else
|
||||||
local to = math.max(line + n, #self.doc.lines)
|
common.splice(highlighter_cache[self], line, n)
|
||||||
for i=line,to do
|
|
||||||
highlighter_cache[self][i] = highlighter_cache[self][i + n]
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -279,7 +264,7 @@ function Highlighter:tokenize_line(idx, state, ...)
|
||||||
if not highlighter_cache[self] then
|
if not highlighter_cache[self] then
|
||||||
highlighter_cache[self] = {}
|
highlighter_cache[self] = {}
|
||||||
end
|
end
|
||||||
highlighter_cache[self][idx] = nil
|
highlighter_cache[self][idx] = false
|
||||||
return res
|
return res
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -305,14 +290,50 @@ end
|
||||||
local MiniMap = Scrollbar:extend()
|
local MiniMap = Scrollbar:extend()
|
||||||
|
|
||||||
|
|
||||||
function MiniMap:new(dv)
|
function MiniMap:new(dv, original_v_scrollbar)
|
||||||
MiniMap.super.new(self, { direction = "v", alignment = "e" })
|
MiniMap.super.new(self, { direction = "v", alignment = "e",
|
||||||
|
force_status = "expanded",
|
||||||
|
expanded_size = cached_settings.width,
|
||||||
|
expanded_margin = 0 })
|
||||||
|
self.original_force_status = original_v_scrollbar.force_status
|
||||||
|
self.original_expanded_size = original_v_scrollbar.expanded_size
|
||||||
|
self.original_expanded_margin = original_v_scrollbar.expanded_margin
|
||||||
self.dv = dv
|
self.dv = dv
|
||||||
self.enabled = nil
|
self.enabled = nil
|
||||||
|
self.was_enabled = true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function MiniMap:line_highlight_color(line_index)
|
function MiniMap:swap_to_status()
|
||||||
|
local enabled = self:is_minimap_enabled()
|
||||||
|
if not enabled and self.was_enabled then
|
||||||
|
self.force_status = self.original_force_status
|
||||||
|
self.expanded_size = self.original_expanded_size
|
||||||
|
self.expanded_margin = self.original_expanded_margin
|
||||||
|
self.was_enabled = false
|
||||||
|
elseif enabled and not self.was_enabled then
|
||||||
|
self.force_status = "expanded"
|
||||||
|
self.expanded_size = cached_settings.width
|
||||||
|
self.expanded_margin = 0
|
||||||
|
self.was_enabled = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function MiniMap:update()
|
||||||
|
self:swap_to_status()
|
||||||
|
if self:is_minimap_enabled() then
|
||||||
|
reset_cache_if_needed()
|
||||||
|
self.expanded_size = cached_settings.width
|
||||||
|
local lh = self.dv:get_line_height()
|
||||||
|
local nlines = self.dv.size.y / lh
|
||||||
|
self.minimum_thumb_size = nlines * line_spacing
|
||||||
|
end
|
||||||
|
MiniMap.super.update(self)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function MiniMap:line_highlight_color(line_index, docview)
|
||||||
-- other plugins can override this, and return a color
|
-- other plugins can override this, and return a color
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -335,97 +356,57 @@ function MiniMap:is_minimap_enabled()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function MiniMap:get_minimap_dimensions()
|
function MiniMap:_on_mouse_pressed_normal(button, x, y, clicks)
|
||||||
local x, y, w, h = self:get_track_rect()
|
local overlaps = self:_overlaps_normal(x, y)
|
||||||
local _, cy, _, cy2 = self.dv:get_content_bounds()
|
local percent = MiniMap.super._on_mouse_pressed_normal(self, button, x, y, clicks)
|
||||||
local lh = self.dv:get_line_height()
|
if overlaps == "track" then
|
||||||
|
-- We need to adjust the percentage to scroll to the line in the minimap
|
||||||
local visible_lines_start = math.max(1, math.floor(cy / lh))
|
-- that was "clicked"
|
||||||
local visible_lines_count = math.max(1, (cy2 - cy) / lh)
|
local minimap_line, _ = self:get_minimap_lines()
|
||||||
local minimap_lines_start = 1
|
local _, track_y, _, _ = self:_get_track_rect_normal()
|
||||||
local minimap_lines_count = math.floor(h / line_spacing)
|
local line = minimap_line + (y - track_y) // line_spacing
|
||||||
local line_count = #self.dv.doc.lines
|
local _, y = self.dv:get_line_screen_position(line)
|
||||||
|
local _, oy = self.dv:get_content_offset()
|
||||||
local is_file_too_large = line_count > 1 and line_count > minimap_lines_count
|
local nr = self.normal_rect
|
||||||
if is_file_too_large then
|
percent = common.clamp((y - oy - (self.dv.size.y) / 2) / (nr.scrollable - self.dv.size.y), 0, 1)
|
||||||
local scroll_pos = (visible_lines_start - 1) /
|
|
||||||
(line_count - visible_lines_count - 1)
|
|
||||||
scroll_pos = math.min(1.0, scroll_pos) -- 0..1, procent of visual area scrolled
|
|
||||||
|
|
||||||
local thumb_height = visible_lines_count * line_spacing
|
|
||||||
local scroll_pos_pixels = scroll_pos * (h - thumb_height)
|
|
||||||
|
|
||||||
minimap_lines_start = visible_lines_start -
|
|
||||||
math.floor(scroll_pos_pixels / line_spacing)
|
|
||||||
minimap_lines_start = math.max(1, minimap_lines_start)
|
|
||||||
end
|
end
|
||||||
return visible_lines_start, visible_lines_count, minimap_lines_start, minimap_lines_count, is_file_too_large
|
return percent
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function MiniMap:_get_track_rect_normal()
|
local function get_visible_minline(dv)
|
||||||
if not self:is_minimap_enabled() then return MiniMap.super._get_track_rect_normal(self) end
|
local _, y, _, _ = dv:get_content_bounds()
|
||||||
return self.dv.size.x + self.dv.position.x - config.plugins.minimap.width, self.dv.position.y, config.plugins.minimap.width, self.dv.size.y
|
local lh = dv:get_line_height()
|
||||||
|
local minline = math.max(0, y / lh + 1)
|
||||||
|
return minline
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function MiniMap:get_active_margin() if self:is_minimap_enabled() then return 0 else return MiniMap.super.get_active_margin(self) end end
|
function MiniMap:get_minimap_lines()
|
||||||
|
local _, track_y, _, h = self:_get_track_rect_normal()
|
||||||
|
local _, thumb_y, _, _ = self:_get_thumb_rect_normal()
|
||||||
|
|
||||||
|
local nlines = h // line_spacing
|
||||||
|
|
||||||
function MiniMap:_get_thumb_rect_normal()
|
local minline = get_visible_minline(self.dv)
|
||||||
if not self:is_minimap_enabled() then return MiniMap.super._get_thumb_rect_normal(self) end
|
local top_lines = (thumb_y - track_y) / line_spacing
|
||||||
local visible_lines_start, visible_lines_count, minimap_lines_start, minimap_lines_count, is_file_too_large = self:get_minimap_dimensions()
|
local lines_start, offset = math.modf(minline - top_lines)
|
||||||
local visible_y = self.dv.position.y + (visible_lines_start - 1) * line_spacing
|
if lines_start <= 1 and nlines >= #self.dv.doc.lines then
|
||||||
if is_file_too_large then
|
offset = 0
|
||||||
local line_count = #self.dv.doc.lines
|
|
||||||
local scroll_pos = (visible_lines_start - 1) /
|
|
||||||
(line_count - visible_lines_count - 1)
|
|
||||||
scroll_pos = math.min(1.0, scroll_pos) -- 0..1, procent of visual area scrolled
|
|
||||||
|
|
||||||
local thumb_height = visible_lines_count * line_spacing
|
|
||||||
local scroll_pos_pixels = scroll_pos * (self.dv.size.y - thumb_height)
|
|
||||||
visible_y = self.dv.position.y + scroll_pos_pixels
|
|
||||||
end
|
end
|
||||||
return self.dv.size.x + self.dv.position.x - config.plugins.minimap.width, visible_y, config.plugins.minimap.width, visible_lines_count * line_spacing
|
return common.clamp(lines_start, 1, #self.dv.doc.lines), common.clamp(nlines, 1, #self.dv.doc.lines), offset * line_spacing
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function MiniMap:on_mouse_pressed(button, x, y, clicks)
|
function MiniMap:set_size(x, y, w, h, scrollable)
|
||||||
local percent = MiniMap.super.on_mouse_pressed(self, button, x, y, clicks)
|
if not self:is_minimap_enabled() then return MiniMap.super.set_size(self, x, y, w, h, scrollable) end
|
||||||
if not self:is_minimap_enabled() or not percent then return percent end
|
-- If possible, use the size needed to only manage the visible minimap lines.
|
||||||
local _, visible_lines_count, minimap_lines_start, minimap_lines_count, is_file_too_large = self:get_minimap_dimensions()
|
-- This allows us to let Scrollbar manage the thumb.
|
||||||
local _, _, w, h = self:get_track_rect()
|
h = math.min(h, line_spacing * (scrollable // self.dv:get_line_height()))
|
||||||
local tx, ty, tw, th = self:get_thumb_rect()
|
MiniMap.super.set_size(self, x, y, w, h, scrollable)
|
||||||
if y >= ty and y < ty + th then self.drag_start_offset = (y - ty) - th / 2 return self.percent end
|
|
||||||
self.drag_start_offset = 0
|
|
||||||
self.hovering.thumb = x >= tx and x < tx + tw and y >= ty and y < ty + th
|
|
||||||
self.dragging = self.hovering.thumb
|
|
||||||
local lh = self.dv:get_line_height()
|
|
||||||
percent = math.max(0.0, math.min((y - self.dv.position.y) / h, 1.0))
|
|
||||||
return (((percent * minimap_lines_count) + minimap_lines_start) * lh / self.dv:get_scrollable_size()) - (visible_lines_count / #self.dv.doc.lines / 2)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function MiniMap:on_mouse_moved(x, y, dx, dy)
|
|
||||||
local percent = MiniMap.super.on_mouse_moved(self, x, y, dx, dy)
|
|
||||||
if not self:is_minimap_enabled() or type(percent) ~= "number" then return percent end
|
|
||||||
local _, visible_lines_count, minimap_lines_start, minimap_lines_count, is_file_too_large = self:get_minimap_dimensions()
|
|
||||||
local lh = self.dv:get_line_height()
|
|
||||||
local _, _, w, h = self:get_track_rect()
|
|
||||||
local tx, ty, tw, th = self:get_thumb_rect()
|
|
||||||
if x >= tx and x < tx + tw and y >= ty and y < ty + th then self.hovering.thumb = true end
|
|
||||||
if not self.hovering.thumb then return self.percent end
|
|
||||||
y = y - self.drag_start_offset
|
|
||||||
percent = math.max(0.0, math.min((y - self.dv.position.y) / h, 1.0))
|
|
||||||
return (((percent * minimap_lines_count) + minimap_lines_start) * lh / self.dv:get_scrollable_size()) - (visible_lines_count / #self.dv.doc.lines / 2)
|
|
||||||
end
|
|
||||||
|
|
||||||
function MiniMap:draw_thumb()
|
|
||||||
local color = self.hovering.thumb and style.scrollbar2 or style.scrollbar
|
|
||||||
local x, y, w, h = self:get_thumb_rect()
|
|
||||||
renderer.draw_rect(x, y, w, h, color)
|
|
||||||
end
|
|
||||||
|
|
||||||
function MiniMap:draw()
|
function MiniMap:draw()
|
||||||
if not self:is_minimap_enabled() then return MiniMap.super.draw(self) end
|
if not self:is_minimap_enabled() then return MiniMap.super.draw(self) end
|
||||||
local dv = self.dv
|
local dv = self.dv
|
||||||
|
@ -434,25 +415,27 @@ function MiniMap:draw()
|
||||||
local highlight = dv.hovered_scrollbar or dv.dragging_scrollbar
|
local highlight = dv.hovered_scrollbar or dv.dragging_scrollbar
|
||||||
local visual_color = highlight and style.scrollbar2 or style.scrollbar
|
local visual_color = highlight and style.scrollbar2 or style.scrollbar
|
||||||
|
|
||||||
local visible_lines_start, visible_lines_count,
|
|
||||||
minimap_lines_start, minimap_lines_count = self:get_minimap_dimensions()
|
|
||||||
|
|
||||||
if config.plugins.minimap.draw_background then
|
if config.plugins.minimap.draw_background then
|
||||||
renderer.draw_rect(x, y, w, h, style.minimap_background or style.background)
|
renderer.draw_rect(x, y, w, self.dv.size.y, style.minimap_background or style.background)
|
||||||
end
|
end
|
||||||
self:draw_thumb()
|
self:draw_thumb()
|
||||||
|
|
||||||
|
local minimap_lines_start, minimap_lines_count, y_offset = self:get_minimap_lines()
|
||||||
|
local line_selection_offset = line_spacing - char_height
|
||||||
|
y = y - y_offset + line_selection_offset
|
||||||
|
|
||||||
-- highlight the selected lines, and the line with the caret on it
|
-- highlight the selected lines, and the line with the caret on it
|
||||||
local selection_color = config.plugins.minimap.selection_color or style.dim
|
local selection_color = config.plugins.minimap.selection_color or style.dim
|
||||||
local caret_color = config.plugins.minimap.caret_color or style.caret
|
local caret_color = config.plugins.minimap.caret_color or style.caret
|
||||||
|
|
||||||
for i, line1, col1, line2, col2 in dv.doc:get_selections() do
|
for _, line1, _, line2, _ in dv.doc:get_selections() do
|
||||||
local selection1_y = y + (line1 - minimap_lines_start) * line_spacing
|
local selection1_y = y + (line1 - minimap_lines_start) * line_spacing - line_selection_offset
|
||||||
local selection2_y = y + (line2 - minimap_lines_start) * line_spacing
|
local selection2_y = y + (line2 - minimap_lines_start) * line_spacing - line_selection_offset
|
||||||
local selection_min_y = math.min(selection1_y, selection2_y)
|
local selection_min_y = math.min(selection1_y, selection2_y)
|
||||||
local selection_h = math.abs(selection2_y - selection1_y)+1
|
local selection_h = math.abs(selection2_y - selection1_y) + 1 + line_selection_offset
|
||||||
renderer.draw_rect(x, selection_min_y, w, selection_h, selection_color)
|
renderer.draw_rect(x, selection_min_y, w, selection_h, selection_color)
|
||||||
renderer.draw_rect(x, selection1_y, w, line_spacing, caret_color)
|
renderer.draw_rect(x, selection1_y, w, line_spacing + line_selection_offset, caret_color)
|
||||||
end
|
end
|
||||||
|
|
||||||
local highlight_align = config.plugins.minimap.highlight_align
|
local highlight_align = config.plugins.minimap.highlight_align
|
||||||
|
@ -519,16 +502,15 @@ function MiniMap:draw()
|
||||||
highlight_x = x + w - highlight_width
|
highlight_x = x + w - highlight_width
|
||||||
end
|
end
|
||||||
local function render_highlight(idx, line_y)
|
local function render_highlight(idx, line_y)
|
||||||
local highlight_color = self:line_highlight_color(idx)
|
local highlight_color = self:line_highlight_color(idx, self.dv)
|
||||||
if highlight_color then
|
if highlight_color then
|
||||||
renderer.draw_rect(highlight_x, line_y, highlight_width, line_spacing, highlight_color)
|
renderer.draw_rect(highlight_x, line_y - line_selection_offset,
|
||||||
|
highlight_width, line_spacing + line_selection_offset, highlight_color)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local endidx = math.min(minimap_lines_start + minimap_lines_count, #self.dv.doc.lines)
|
local endidx = math.min(minimap_lines_start + minimap_lines_count, #self.dv.doc.lines)
|
||||||
|
|
||||||
reset_cache_if_needed()
|
|
||||||
|
|
||||||
if not highlighter_cache[dv.doc.highlighter] then
|
if not highlighter_cache[dv.doc.highlighter] then
|
||||||
highlighter_cache[dv.doc.highlighter] = {}
|
highlighter_cache[dv.doc.highlighter] = {}
|
||||||
end
|
end
|
||||||
|
@ -603,23 +585,9 @@ end
|
||||||
local old_docview_new = DocView.new
|
local old_docview_new = DocView.new
|
||||||
function DocView:new(doc)
|
function DocView:new(doc)
|
||||||
old_docview_new(self, doc)
|
old_docview_new(self, doc)
|
||||||
if self:is(DocView) then self.v_scrollbar = MiniMap(self) end
|
if self:is(DocView) then
|
||||||
|
self.v_scrollbar = MiniMap(self, self.v_scrollbar)
|
||||||
end
|
end
|
||||||
|
|
||||||
local old_docview_scroll_to_make_visible = DocView.scroll_to_make_visible
|
|
||||||
function DocView:scroll_to_make_visible(line, col, ...)
|
|
||||||
if
|
|
||||||
not self:is(DocView) or not self.v_scrollbar:is(MiniMap)
|
|
||||||
or
|
|
||||||
not self.v_scrollbar:is_minimap_enabled()
|
|
||||||
then
|
|
||||||
return old_docview_scroll_to_make_visible(self, line, col, ...)
|
|
||||||
end
|
|
||||||
local old_size = self.size.x
|
|
||||||
self.size.x = math.max(0, self.size.x - config.plugins.minimap.width)
|
|
||||||
local result = old_docview_scroll_to_make_visible(self, line, col, ...)
|
|
||||||
self.size.x = old_size
|
|
||||||
return result
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
@ -663,4 +631,3 @@ command.add("core.docview!", {
|
||||||
})
|
})
|
||||||
|
|
||||||
return MiniMap
|
return MiniMap
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
-- mod-version:3
|
||||||
|
local core = require "core"
|
||||||
|
local command = require "core.command"
|
||||||
|
local translate = require "core.doc.translate"
|
||||||
|
|
||||||
|
local function split_lines(text)
|
||||||
|
local res = {}
|
||||||
|
for line in (text .. "\n"):gmatch("(.-)\n") do
|
||||||
|
table.insert(res, line)
|
||||||
|
end
|
||||||
|
return res
|
||||||
|
end
|
||||||
|
|
||||||
|
command.add("core.docview!", {
|
||||||
|
["sort:sort"] = function(dv)
|
||||||
|
local doc = dv.doc
|
||||||
|
|
||||||
|
local l1, c1, l2, c2, swap = doc:get_selection(true)
|
||||||
|
l1, c1 = translate.start_of_line(doc, l1, c1)
|
||||||
|
l2, c2 = translate.end_of_line(doc, l2, c2)
|
||||||
|
doc:set_selection(l1, c1, l2, c2, swap)
|
||||||
|
|
||||||
|
doc:replace(function(text)
|
||||||
|
local head, body, foot = text:match("(\n*)(.-)(\n*)$")
|
||||||
|
local lines = split_lines(body)
|
||||||
|
table.sort(lines, function(a, b) return a:lower() < b:lower() end)
|
||||||
|
return head .. table.concat(lines, "\n") .. foot, 1
|
||||||
|
end)
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
|
|
@ -0,0 +1,413 @@
|
||||||
|
-- mod-version:3
|
||||||
|
|
||||||
|
--[[
|
||||||
|
Lite-XL plugin to sort CSS properties alphabetically or using
|
||||||
|
the concentric model by https://rhodesmill.org/brandon/2011/concentric-css/
|
||||||
|
|
||||||
|
This plugin is based on vscode plugin: https://github.com/roubaobaozi/vscode-sort-selection-concentrically
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
1. Select CSS code (must have one property per line).
|
||||||
|
2. Press control+alt+a to sort alphabetically or control+alt+c to sort concentrically.
|
||||||
|
Alternatively you can also right-click and select the appropriate option.
|
||||||
|
--]]
|
||||||
|
|
||||||
|
local core = require "core"
|
||||||
|
local config = require "core.config"
|
||||||
|
local common = require "core.common"
|
||||||
|
local command = require "core.command"
|
||||||
|
local keymap = require "core.keymap"
|
||||||
|
local contextmenu = require "plugins.contextmenu"
|
||||||
|
|
||||||
|
local css_syntaxes = {
|
||||||
|
"CSS",
|
||||||
|
"HTML",
|
||||||
|
"JSX",
|
||||||
|
"TypeScript with JSX",
|
||||||
|
}
|
||||||
|
|
||||||
|
local concentric_order = {
|
||||||
|
-- browser default styles
|
||||||
|
"all",
|
||||||
|
"appearance",
|
||||||
|
|
||||||
|
-- box model
|
||||||
|
"box-sizing",
|
||||||
|
|
||||||
|
-- position
|
||||||
|
"display",
|
||||||
|
"position",
|
||||||
|
"top",
|
||||||
|
"right",
|
||||||
|
"bottom",
|
||||||
|
"left",
|
||||||
|
|
||||||
|
"float",
|
||||||
|
"clear",
|
||||||
|
|
||||||
|
-- flex
|
||||||
|
"flex",
|
||||||
|
"flex-basis",
|
||||||
|
"flex-direction",
|
||||||
|
"flex-flow",
|
||||||
|
"flex-grow",
|
||||||
|
"flex-shrink",
|
||||||
|
"flex-wrap",
|
||||||
|
|
||||||
|
-- grid
|
||||||
|
"grid",
|
||||||
|
"grid-area",
|
||||||
|
"grid-template",
|
||||||
|
"grid-template-areas",
|
||||||
|
"grid-template-rows",
|
||||||
|
"grid-template-columns",
|
||||||
|
"grid-row",
|
||||||
|
"grid-row-start",
|
||||||
|
"grid-row-end",
|
||||||
|
"grid-column",
|
||||||
|
"grid-column-start",
|
||||||
|
"grid-column-end",
|
||||||
|
"grid-auto-rows",
|
||||||
|
"grid-auto-columns",
|
||||||
|
"grid-auto-flow",
|
||||||
|
"grid-gap",
|
||||||
|
"grid-row-gap",
|
||||||
|
"grid-column-gap",
|
||||||
|
|
||||||
|
-- flex align
|
||||||
|
"align-content",
|
||||||
|
"align-items",
|
||||||
|
"align-self",
|
||||||
|
|
||||||
|
-- flex justify
|
||||||
|
"justify-content",
|
||||||
|
"justify-items",
|
||||||
|
"justify-self",
|
||||||
|
|
||||||
|
-- order
|
||||||
|
"order",
|
||||||
|
|
||||||
|
-- columns
|
||||||
|
"columns",
|
||||||
|
"column-gap",
|
||||||
|
"column-fill",
|
||||||
|
"column-rule",
|
||||||
|
"column-rule-width",
|
||||||
|
"column-rule-style",
|
||||||
|
"column-rule-color",
|
||||||
|
"column-span",
|
||||||
|
"column-count",
|
||||||
|
"column-width",
|
||||||
|
|
||||||
|
-- transform
|
||||||
|
"backface-visibility",
|
||||||
|
"perspective",
|
||||||
|
"perspective-origin",
|
||||||
|
"transform",
|
||||||
|
"transform-origin",
|
||||||
|
"transform-style",
|
||||||
|
|
||||||
|
-- transitions
|
||||||
|
"transition",
|
||||||
|
"transition-delay",
|
||||||
|
"transition-duration",
|
||||||
|
"transition-property",
|
||||||
|
"transition-timing-function",
|
||||||
|
|
||||||
|
-- visibility
|
||||||
|
"visibility",
|
||||||
|
"opacity",
|
||||||
|
"mix-blend-mode",
|
||||||
|
"isolation",
|
||||||
|
"z-index",
|
||||||
|
|
||||||
|
-- margin
|
||||||
|
"margin",
|
||||||
|
"margin-top",
|
||||||
|
"margin-right",
|
||||||
|
"margin-bottom",
|
||||||
|
"margin-left",
|
||||||
|
|
||||||
|
-- outline
|
||||||
|
"outline",
|
||||||
|
"outline-offset",
|
||||||
|
"outline-width",
|
||||||
|
"outline-style",
|
||||||
|
"outline-color",
|
||||||
|
|
||||||
|
-- border
|
||||||
|
"border",
|
||||||
|
"border-top",
|
||||||
|
"border-right",
|
||||||
|
"border-bottom",
|
||||||
|
"border-left",
|
||||||
|
"border-width",
|
||||||
|
"border-top-width",
|
||||||
|
"border-right-width",
|
||||||
|
"border-bottom-width",
|
||||||
|
"border-left-width",
|
||||||
|
|
||||||
|
-- border-style
|
||||||
|
"border-style",
|
||||||
|
"border-top-style",
|
||||||
|
"border-right-style",
|
||||||
|
"border-bottom-style",
|
||||||
|
"border-left-style",
|
||||||
|
|
||||||
|
-- border-radius
|
||||||
|
"border-radius",
|
||||||
|
"border-top-left-radius",
|
||||||
|
"border-top-right-radius",
|
||||||
|
"border-bottom-left-radius",
|
||||||
|
"border-bottom-right-radius",
|
||||||
|
|
||||||
|
-- border-color
|
||||||
|
"border-color",
|
||||||
|
"border-top-color",
|
||||||
|
"border-right-color",
|
||||||
|
"border-bottom-color",
|
||||||
|
"border-left-color",
|
||||||
|
|
||||||
|
-- border-image
|
||||||
|
"border-image",
|
||||||
|
"border-image-source",
|
||||||
|
"border-image-width",
|
||||||
|
"border-image-outset",
|
||||||
|
"border-image-repeat",
|
||||||
|
"border-image-slice",
|
||||||
|
|
||||||
|
-- box-shadow
|
||||||
|
"box-shadow",
|
||||||
|
|
||||||
|
-- background
|
||||||
|
"background",
|
||||||
|
"background-attachment",
|
||||||
|
"background-clip",
|
||||||
|
"background-color",
|
||||||
|
"background-image",
|
||||||
|
"background-origin",
|
||||||
|
"background-position",
|
||||||
|
"background-repeat",
|
||||||
|
"background-size",
|
||||||
|
"background-blend-mode",
|
||||||
|
|
||||||
|
-- cursor
|
||||||
|
"cursor",
|
||||||
|
|
||||||
|
-- padding
|
||||||
|
"padding",
|
||||||
|
"padding-top",
|
||||||
|
"padding-right",
|
||||||
|
"padding-bottom",
|
||||||
|
"padding-left",
|
||||||
|
|
||||||
|
-- width
|
||||||
|
"width",
|
||||||
|
"min-width",
|
||||||
|
"max-width",
|
||||||
|
|
||||||
|
-- height
|
||||||
|
"height",
|
||||||
|
"min-height",
|
||||||
|
"max-height",
|
||||||
|
|
||||||
|
-- overflow
|
||||||
|
"overflow",
|
||||||
|
"overflow-x",
|
||||||
|
"overflow-y",
|
||||||
|
"resize",
|
||||||
|
|
||||||
|
-- list-style
|
||||||
|
"list-style",
|
||||||
|
"list-style-type",
|
||||||
|
"list-style-position",
|
||||||
|
"list-style-image",
|
||||||
|
"caption-side",
|
||||||
|
|
||||||
|
-- tables
|
||||||
|
"table-layout",
|
||||||
|
"border-collapse",
|
||||||
|
"border-spacing",
|
||||||
|
"empty-cells",
|
||||||
|
|
||||||
|
-- animation
|
||||||
|
"animation",
|
||||||
|
"animation-name",
|
||||||
|
"animation-duration",
|
||||||
|
"animation-timing-function",
|
||||||
|
"animation-delay",
|
||||||
|
"animation-iteration-count",
|
||||||
|
"animation-direction",
|
||||||
|
"animation-fill-mode",
|
||||||
|
"animation-play-state",
|
||||||
|
|
||||||
|
-- vertical-alignment
|
||||||
|
"vertical-align",
|
||||||
|
|
||||||
|
-- text-alignment & decoration
|
||||||
|
"direction",
|
||||||
|
"tab-size",
|
||||||
|
"text-align",
|
||||||
|
"text-align-last",
|
||||||
|
"text-justify",
|
||||||
|
"text-indent",
|
||||||
|
"text-transform",
|
||||||
|
"text-decoration",
|
||||||
|
"text-decoration-color",
|
||||||
|
"text-decoration-line",
|
||||||
|
"text-decoration-style",
|
||||||
|
"text-rendering",
|
||||||
|
"text-shadow",
|
||||||
|
"text-overflow",
|
||||||
|
|
||||||
|
-- text-spacing
|
||||||
|
"line-height",
|
||||||
|
"word-spacing",
|
||||||
|
"letter-spacing",
|
||||||
|
"white-space",
|
||||||
|
"word-break",
|
||||||
|
"word-wrap",
|
||||||
|
"color",
|
||||||
|
|
||||||
|
-- font
|
||||||
|
"font",
|
||||||
|
"font-family",
|
||||||
|
"font-kerning",
|
||||||
|
"font-size",
|
||||||
|
"font-size-adjust",
|
||||||
|
"font-stretch",
|
||||||
|
"font-weight",
|
||||||
|
"font-smoothing",
|
||||||
|
"osx-font-smoothing",
|
||||||
|
"font-variant",
|
||||||
|
"font-style",
|
||||||
|
|
||||||
|
-- content
|
||||||
|
"content",
|
||||||
|
"quotes",
|
||||||
|
|
||||||
|
-- counters
|
||||||
|
"counter-reset",
|
||||||
|
"counter-increment",
|
||||||
|
|
||||||
|
-- breaks
|
||||||
|
"page-break-before",
|
||||||
|
"page-break-after",
|
||||||
|
"page-break-inside",
|
||||||
|
|
||||||
|
-- mouse
|
||||||
|
"pointer-events",
|
||||||
|
|
||||||
|
-- intent
|
||||||
|
"will-change"
|
||||||
|
}
|
||||||
|
|
||||||
|
config.plugins.sortcss = common.merge({
|
||||||
|
css_syntaxes = css_syntaxes,
|
||||||
|
concentric_order = concentric_order,
|
||||||
|
-- The config specification used by the settings gui
|
||||||
|
config_spec = {
|
||||||
|
name = "Sort CSS",
|
||||||
|
{
|
||||||
|
label = "CSS file syntaxes",
|
||||||
|
description = "List of CSS-compatible syntax names.",
|
||||||
|
path = "css_syntaxes",
|
||||||
|
type = "list_strings",
|
||||||
|
default = css_syntaxes
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}, config.plugins.sortcss)
|
||||||
|
|
||||||
|
local function compare_alphabetical(line1, line2)
|
||||||
|
local prop1 = line1:match("^%s*([^:]+)")
|
||||||
|
local prop2 = line2:match("^%s*([^:]+)")
|
||||||
|
|
||||||
|
return string.lower(prop1) < string.lower(prop2)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function compare_concentrical(line1, line2)
|
||||||
|
local prop1 = line1:match("^%s*([^:]+)")
|
||||||
|
local prop2 = line2:match("^%s*([^:]+)")
|
||||||
|
|
||||||
|
local index1 = 0
|
||||||
|
local index2 = 0
|
||||||
|
|
||||||
|
for i, prop in ipairs(config.plugins.sortcss.concentric_order) do
|
||||||
|
if prop == prop1 then
|
||||||
|
index1 = i
|
||||||
|
end
|
||||||
|
if prop == prop2 then
|
||||||
|
index2 = i
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if index1 == 0 then
|
||||||
|
index1 = #concentric_order + 1
|
||||||
|
end
|
||||||
|
|
||||||
|
if index2 == 0 then
|
||||||
|
index2 = #concentric_order + 1
|
||||||
|
end
|
||||||
|
|
||||||
|
return index1 < index2
|
||||||
|
end
|
||||||
|
|
||||||
|
local function sort_css(str, order)
|
||||||
|
local lines = {}
|
||||||
|
for line in str:gmatch("[^\r\n]+") do
|
||||||
|
table.insert(lines, line)
|
||||||
|
end
|
||||||
|
|
||||||
|
if order == "alphabetical" then
|
||||||
|
table.sort(lines, compare_alphabetical)
|
||||||
|
end
|
||||||
|
|
||||||
|
if order == "concentrical" then
|
||||||
|
table.sort(lines, compare_concentrical)
|
||||||
|
end
|
||||||
|
|
||||||
|
return table.concat(lines, "\n")
|
||||||
|
end
|
||||||
|
|
||||||
|
command.add("core.docview", {
|
||||||
|
["sortcss:alphabetical"] = function(dv)
|
||||||
|
local doc = dv.doc
|
||||||
|
if not doc:has_selection() then
|
||||||
|
core.error("No text selected")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local text = doc:get_text(doc:get_selection())
|
||||||
|
doc:text_input(sort_css(text, "alphabetical"))
|
||||||
|
end,
|
||||||
|
["sortcss:concentrical"] = function(dv)
|
||||||
|
local doc = dv.doc
|
||||||
|
if not doc:has_selection() then
|
||||||
|
core.error("No text selected")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local text = doc:get_text(doc:get_selection())
|
||||||
|
doc:text_input(sort_css(text, "concentrical"))
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
|
||||||
|
contextmenu:register(function()
|
||||||
|
local doc = core.active_view.doc
|
||||||
|
if doc and doc:has_selection() then
|
||||||
|
for _, v in pairs(config.plugins.sortcss.css_syntaxes) do
|
||||||
|
if v == doc.syntax.name then
|
||||||
|
return true, core.active_view
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return false
|
||||||
|
end, {
|
||||||
|
contextmenu.DIVIDER,
|
||||||
|
{ text = "Sort CSS Selection Alphabetically", command = "sortcss:alphabetical" },
|
||||||
|
{ text = "Sort CSS Selection Concentrically", command = "sortcss:concentrical" },
|
||||||
|
})
|
||||||
|
|
||||||
|
keymap.add { ["ctrl+alt+a"] = "sortcss:alphabetical" }
|
||||||
|
keymap.add { ["ctrl+alt+c"] = "sortcss:concentrical" }
|
|
@ -0,0 +1,820 @@
|
||||||
|
-- mod-version:3
|
||||||
|
local core = require "core"
|
||||||
|
local common = require "core.common"
|
||||||
|
local command = require "core.command"
|
||||||
|
local config = require "core.config"
|
||||||
|
local keymap = require "core.keymap"
|
||||||
|
local style = require "core.style"
|
||||||
|
local View = require "core.view"
|
||||||
|
local CommandView = require "core.commandview"
|
||||||
|
local DocView = require "core.docview"
|
||||||
|
|
||||||
|
local TodoTreeView = View:extend()
|
||||||
|
|
||||||
|
local SCOPES = {
|
||||||
|
ALL = "all",
|
||||||
|
FOCUSED = "focused",
|
||||||
|
}
|
||||||
|
|
||||||
|
config.plugins.todotreeview = common.merge({
|
||||||
|
todo_tags = {"TODO", "BUG", "FIX", "FIXME", "IMPROVEMENT"},
|
||||||
|
tag_colors = {
|
||||||
|
TODO = {tag=style.text, tag_hover=style.accent, text=style.text, text_hover=style.accent},
|
||||||
|
BUG = {tag=style.text, tag_hover=style.accent, text=style.text, text_hover=style.accent},
|
||||||
|
FIX = {tag=style.text, tag_hover=style.accent, text=style.text, text_hover=style.accent},
|
||||||
|
FIXME = {tag=style.text, tag_hover=style.accent, text=style.text, text_hover=style.accent},
|
||||||
|
IMPROVEMENT = {tag=style.text, tag_hover=style.accent, text=style.text, text_hover=style.accent},
|
||||||
|
},
|
||||||
|
todo_file_color = {
|
||||||
|
name=style.text,
|
||||||
|
hover=style.accent
|
||||||
|
},
|
||||||
|
-- Paths or files to be ignored
|
||||||
|
ignore_paths = {},
|
||||||
|
|
||||||
|
-- Tells if the plugin should start with the nodes expanded
|
||||||
|
todo_expanded = true,
|
||||||
|
|
||||||
|
-- 'tag' mode can be used to group the todos by tags
|
||||||
|
-- 'file' mode can be used to group the todos by files
|
||||||
|
-- 'file_tag' mode can be used to group the todos by files and then by tags inside the files
|
||||||
|
todo_mode = "tag",
|
||||||
|
|
||||||
|
treeview_size = 200 * SCALE, -- default size
|
||||||
|
|
||||||
|
-- Only used in file mode when the tag and the text are on the same line
|
||||||
|
todo_separator = " - ",
|
||||||
|
|
||||||
|
-- Text displayed when the note is empty
|
||||||
|
todo_default_text = "blank",
|
||||||
|
|
||||||
|
-- Scope of the displayed tags
|
||||||
|
-- 'all' scope to show all tags from the project all the time
|
||||||
|
-- 'focused' scope to show the tags from the currently focused file
|
||||||
|
todo_scope = SCOPES.ALL,
|
||||||
|
|
||||||
|
-- The config specification used by the settings gui
|
||||||
|
config_spec = {
|
||||||
|
name = "TodoTreeView",
|
||||||
|
{
|
||||||
|
label = "Todo Tags",
|
||||||
|
description = "List of tags to parse and show in the todo panel.",
|
||||||
|
path = "todo_tags",
|
||||||
|
type = "list_strings",
|
||||||
|
default = {"TODO", "BUG", "FIX", "FIXME", "IMPROVEMENT"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label = "Paths to ignore",
|
||||||
|
description = "Paths to be ignored when parsing the tags.",
|
||||||
|
path = "ignore_paths",
|
||||||
|
type = "list_strings",
|
||||||
|
default = {}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label = "Groups Expanded",
|
||||||
|
description = "Defines if the groups (Tags / Files) should start expanded.",
|
||||||
|
path = "todo_expanded",
|
||||||
|
type = "toggle",
|
||||||
|
default = true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label = "Mode for the todos",
|
||||||
|
description = "Mode for the todos to be displayed.",
|
||||||
|
path = "todo_mode",
|
||||||
|
type = "selection",
|
||||||
|
default = "tag",
|
||||||
|
values = {
|
||||||
|
{"Tag", "tag"},
|
||||||
|
{"File", "file"},
|
||||||
|
{"FileTag", "file_tag"}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label = "Treeview Size",
|
||||||
|
description = "Size of the todo tree view panel.",
|
||||||
|
path = "treeview_size",
|
||||||
|
type = "number",
|
||||||
|
default = 200 * SCALE,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label = "Todo separator",
|
||||||
|
description = "Separator used in file mode when the tag and the text are on the same line.",
|
||||||
|
path = "todo_separator",
|
||||||
|
type = "string",
|
||||||
|
default = " - ",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label = "Empty Default Text",
|
||||||
|
description = "Default text displayed for a note when it has no text.",
|
||||||
|
path = "todo_default_text",
|
||||||
|
type = "string",
|
||||||
|
default = " - ",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label = "Todo Scope",
|
||||||
|
description = "Scope for the notes to be picked, all notes or currently focused file.",
|
||||||
|
path = "todo_scope",
|
||||||
|
type = "selection",
|
||||||
|
default = "all",
|
||||||
|
values = {
|
||||||
|
{"All", "all"},
|
||||||
|
{"Focused", "focused"},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}, config.plugins.todotreeview)
|
||||||
|
|
||||||
|
local icon_small_font = style.icon_font:copy(10 * SCALE)
|
||||||
|
|
||||||
|
function TodoTreeView:new()
|
||||||
|
TodoTreeView.super.new(self)
|
||||||
|
self.scrollable = true
|
||||||
|
self.focusable = false
|
||||||
|
self.visible = true
|
||||||
|
self.times_cache = {}
|
||||||
|
self.cache = {}
|
||||||
|
self.cache_updated = false
|
||||||
|
self.init_size = true
|
||||||
|
self.focus_index = 0
|
||||||
|
self.filter = ""
|
||||||
|
self.previous_focused_file = nil
|
||||||
|
|
||||||
|
-- Items are generated from cache according to the mode
|
||||||
|
self.items = {}
|
||||||
|
end
|
||||||
|
|
||||||
|
local function is_file_ignored(filename)
|
||||||
|
for _, path in ipairs(config.plugins.todotreeview.ignore_paths) do
|
||||||
|
local s, _ = filename:find(path)
|
||||||
|
if s then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
function TodoTreeView:is_file_in_scope(filename)
|
||||||
|
if config.plugins.todotreeview.todo_scope == SCOPES.ALL then
|
||||||
|
return true
|
||||||
|
elseif config.plugins.todotreeview.todo_scope == SCOPES.FOCUSED then
|
||||||
|
if core.active_view:is(CommandView) or core.active_view:is(TodoTreeView) then
|
||||||
|
if self.previous_focused_file then
|
||||||
|
return self.previous_focused_file == filename
|
||||||
|
end
|
||||||
|
elseif core.active_view:is(DocView) then
|
||||||
|
return core.active_view.doc.filename == filename
|
||||||
|
end
|
||||||
|
return true
|
||||||
|
else
|
||||||
|
assert(false, "Unknown scope defined ("..config.plugins.todotreeview.todo_scope..")")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function TodoTreeView.get_all_files()
|
||||||
|
local all_files = {}
|
||||||
|
for _, file in ipairs(core.project_files) do
|
||||||
|
if file.filename then
|
||||||
|
all_files[file.filename] = file
|
||||||
|
end
|
||||||
|
end
|
||||||
|
for _, file in ipairs(core.docs) do
|
||||||
|
if file.filename and not all_files[file.filename] then
|
||||||
|
all_files[file.filename] = {
|
||||||
|
filename = file.filename,
|
||||||
|
type = "file"
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return all_files
|
||||||
|
end
|
||||||
|
|
||||||
|
function TodoTreeView:refresh_cache()
|
||||||
|
local items = {}
|
||||||
|
if not next(self.items) then
|
||||||
|
items = self.items
|
||||||
|
end
|
||||||
|
self.updating_cache = true
|
||||||
|
|
||||||
|
core.add_thread(function()
|
||||||
|
for _, item in pairs(self.get_all_files()) do
|
||||||
|
local ignored = is_file_ignored(item.filename)
|
||||||
|
if not ignored and item.type == "file" then
|
||||||
|
local cached = self:get_cached(item)
|
||||||
|
|
||||||
|
if config.plugins.todotreeview.todo_mode == "file" then
|
||||||
|
items[cached.filename] = cached
|
||||||
|
elseif config.plugins.todotreeview.todo_mode == "file_tag" then
|
||||||
|
local file_t = {}
|
||||||
|
file_t.expanded = config.plugins.todotreeview.todo_expanded
|
||||||
|
file_t.type = "file"
|
||||||
|
file_t.tags = {}
|
||||||
|
file_t.todos = {}
|
||||||
|
file_t.filename = cached.filename
|
||||||
|
file_t.abs_filename = cached.abs_filename
|
||||||
|
items[cached.filename] = file_t
|
||||||
|
for _, todo in ipairs(cached.todos) do
|
||||||
|
local tag = todo.tag
|
||||||
|
if not file_t.tags[tag] then
|
||||||
|
local tag_t = {}
|
||||||
|
tag_t.expanded = config.plugins.todotreeview.todo_expanded
|
||||||
|
tag_t.type = "group"
|
||||||
|
tag_t.todos = {}
|
||||||
|
tag_t.tag = tag
|
||||||
|
file_t.tags[tag] = tag_t
|
||||||
|
end
|
||||||
|
|
||||||
|
table.insert(file_t.tags[tag].todos, todo)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
for _, todo in ipairs(cached.todos) do
|
||||||
|
local tag = todo.tag
|
||||||
|
if not items[tag] then
|
||||||
|
local t = {}
|
||||||
|
t.expanded = config.plugins.todotreeview.todo_expanded
|
||||||
|
t.type = "group"
|
||||||
|
t.todos = {}
|
||||||
|
t.tag = tag
|
||||||
|
items[tag] = t
|
||||||
|
end
|
||||||
|
|
||||||
|
table.insert(items[tag].todos, todo)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Copy expanded from old items
|
||||||
|
if config.plugins.todotreeview.todo_mode == "tag" and next(self.items) then
|
||||||
|
for tag, data in pairs(self.items) do
|
||||||
|
if items[tag] then
|
||||||
|
items[tag].expanded = data.expanded
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
self.items = items
|
||||||
|
core.redraw = true
|
||||||
|
self.cache_updated = true
|
||||||
|
self.updating_cache = false
|
||||||
|
end, self)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
local function find_file_todos(t, filename)
|
||||||
|
local fp = io.open(filename)
|
||||||
|
if not fp then return t end
|
||||||
|
local n = 1
|
||||||
|
for line in fp:lines() do
|
||||||
|
for _, todo_tag in ipairs(config.plugins.todotreeview.todo_tags) do
|
||||||
|
-- Add spaces at the start and end of line so the pattern will pick
|
||||||
|
-- tags at the start and at the end of lines
|
||||||
|
local extended_line = " "..line.." "
|
||||||
|
local match_str = "[^a-zA-Z_\"'`]"..todo_tag.."[^\"'a-zA-Z_`]+"
|
||||||
|
local s, e = extended_line:find(match_str)
|
||||||
|
if s then
|
||||||
|
local d = {}
|
||||||
|
d.type = "todo"
|
||||||
|
d.tag = todo_tag
|
||||||
|
d.filename = filename
|
||||||
|
d.text = extended_line:sub(e+1)
|
||||||
|
if d.text == "" then
|
||||||
|
d.text = config.plugins.todotreeview.todo_default_text
|
||||||
|
end
|
||||||
|
d.line = n
|
||||||
|
d.col = s
|
||||||
|
table.insert(t, d)
|
||||||
|
end
|
||||||
|
core.redraw = true
|
||||||
|
end
|
||||||
|
if n % 100 == 0 then coroutine.yield() end
|
||||||
|
n = n + 1
|
||||||
|
core.redraw = true
|
||||||
|
end
|
||||||
|
fp:close()
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function TodoTreeView:get_cached(item)
|
||||||
|
local t = self.cache[item.filename]
|
||||||
|
if not t then
|
||||||
|
t = {}
|
||||||
|
t.expanded = config.plugins.todotreeview.todo_expanded
|
||||||
|
t.filename = item.filename
|
||||||
|
t.abs_filename = system.absolute_path(item.filename)
|
||||||
|
t.type = item.type
|
||||||
|
t.todos = {}
|
||||||
|
t.tags = {}
|
||||||
|
find_file_todos(t.todos, t.filename)
|
||||||
|
self.cache[t.filename] = t
|
||||||
|
end
|
||||||
|
return t
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function TodoTreeView:get_name()
|
||||||
|
return "Todo Tree"
|
||||||
|
end
|
||||||
|
|
||||||
|
function TodoTreeView:set_target_size(axis, value)
|
||||||
|
if axis == "x" then
|
||||||
|
config.plugins.todotreeview.treeview_size = value
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function TodoTreeView:get_item_height()
|
||||||
|
return style.font:get_height() + style.padding.y
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function TodoTreeView:get_cached_time(doc)
|
||||||
|
local t = self.times_cache[doc]
|
||||||
|
if not t then
|
||||||
|
local info = system.get_file_info(doc.filename)
|
||||||
|
if not info then return nil end
|
||||||
|
self.times_cache[doc] = info.modified
|
||||||
|
end
|
||||||
|
return t
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function TodoTreeView:check_cache()
|
||||||
|
local existing_docs = {}
|
||||||
|
for _, doc in ipairs(core.docs) do
|
||||||
|
if doc.filename then
|
||||||
|
existing_docs[doc.filename] = true
|
||||||
|
local info = system.get_file_info(doc.filename)
|
||||||
|
local cached = self:get_cached_time(doc)
|
||||||
|
if not info and cached then
|
||||||
|
-- document deleted
|
||||||
|
self.times_cache[doc] = nil
|
||||||
|
self.cache[doc.filename] = nil
|
||||||
|
self.cache_updated = false
|
||||||
|
elseif cached and cached ~= info.modified then
|
||||||
|
-- document modified
|
||||||
|
self.times_cache[doc] = info.modified
|
||||||
|
self.cache[doc.filename] = nil
|
||||||
|
self.cache_updated = false
|
||||||
|
elseif not cached then
|
||||||
|
self.cache_updated = false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
for _, file in ipairs(core.project_files) do
|
||||||
|
existing_docs[file.filename] = true
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Check for docs in cache that may not exist anymore
|
||||||
|
-- for example: (Openend from outside of project and closed)
|
||||||
|
for filename, doc in pairs(self.cache) do
|
||||||
|
local exists = existing_docs[filename]
|
||||||
|
if not exists then
|
||||||
|
self.times_cache[doc] = nil
|
||||||
|
self.cache[filename] = nil
|
||||||
|
self.cache_updated = false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if core.project_files ~= self.last_project_files then
|
||||||
|
self.last_project_files = core.project_files
|
||||||
|
self.cache_updated = false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function TodoTreeView:each_item()
|
||||||
|
self:check_cache()
|
||||||
|
if not self.updating_cache and not self.cache_updated then
|
||||||
|
self:refresh_cache()
|
||||||
|
end
|
||||||
|
|
||||||
|
return coroutine.wrap(function()
|
||||||
|
local ox, oy = self:get_content_offset()
|
||||||
|
local y = oy + style.padding.y
|
||||||
|
local w = self.size.x
|
||||||
|
local h = self:get_item_height()
|
||||||
|
|
||||||
|
for filename, item in pairs(self.items) do
|
||||||
|
local in_scope = item.type == "group" or self:is_file_in_scope(item.filename)
|
||||||
|
if in_scope and #item.todos > 0 then
|
||||||
|
coroutine.yield(item, ox, y, w, h)
|
||||||
|
y = y + h
|
||||||
|
|
||||||
|
for _, todo in ipairs(item.todos) do
|
||||||
|
if item.expanded then
|
||||||
|
local in_todo = string.find(todo.text:lower(), self.filter:lower())
|
||||||
|
local todo_in_scope = self:is_file_in_scope(todo.filename)
|
||||||
|
if todo_in_scope and (#self.filter == 0 or in_todo) then
|
||||||
|
coroutine.yield(todo, ox, y, w, h)
|
||||||
|
y = y + h
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
if in_scope and item.tags then
|
||||||
|
local first_tag = true
|
||||||
|
for _, tag in pairs(item.tags) do
|
||||||
|
if first_tag then
|
||||||
|
coroutine.yield(item, ox, y, w, h)
|
||||||
|
y = y + h
|
||||||
|
first_tag = false
|
||||||
|
end
|
||||||
|
if item.expanded then
|
||||||
|
coroutine.yield(tag, ox, y, w, h)
|
||||||
|
y = y + h
|
||||||
|
|
||||||
|
for _, todo in ipairs(tag.todos) do
|
||||||
|
if item.expanded and tag.expanded then
|
||||||
|
local in_todo = string.find(todo.text:lower(), self.filter:lower())
|
||||||
|
local todo_in_scope = self:is_file_in_scope(todo.filename)
|
||||||
|
if todo_in_scope and (#self.filter == 0 or in_todo) then
|
||||||
|
coroutine.yield(todo, ox, y, w, h)
|
||||||
|
y = y + h
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function TodoTreeView:on_mouse_moved(px, py)
|
||||||
|
self.hovered_item = nil
|
||||||
|
for item, x,y,w,h in self:each_item() do
|
||||||
|
if px > x and py > y and px <= x + w and py <= y + h then
|
||||||
|
self.hovered_item = item
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function TodoTreeView:goto_hovered_item()
|
||||||
|
if not self.hovered_item then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
if self.hovered_item.type == "group" or self.hovered_item.type == "file" then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
core.try(function()
|
||||||
|
local i = self.hovered_item
|
||||||
|
local dv = core.root_view:open_doc(core.open_doc(i.filename))
|
||||||
|
core.root_view.root_node:update_layout()
|
||||||
|
dv.doc:set_selection(i.line, i.col)
|
||||||
|
dv:scroll_to_line(i.line, false, true)
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
function TodoTreeView:on_mouse_pressed(button, x, y)
|
||||||
|
if not self.hovered_item then
|
||||||
|
return
|
||||||
|
elseif self.hovered_item.type == "file"
|
||||||
|
or self.hovered_item.type == "group" then
|
||||||
|
self.hovered_item.expanded = not self.hovered_item.expanded
|
||||||
|
else
|
||||||
|
self:goto_hovered_item()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function TodoTreeView:update()
|
||||||
|
-- Update focus
|
||||||
|
if core.active_view:is(DocView) then
|
||||||
|
self.previous_focused_file = core.active_view.doc.filename
|
||||||
|
elseif core.active_view:is(CommandView) or core.active_view:is(TodoTreeView) then
|
||||||
|
-- Do nothing
|
||||||
|
else
|
||||||
|
self.previous_focused_file = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
self.scroll.to.y = math.max(0, self.scroll.to.y)
|
||||||
|
|
||||||
|
-- update width
|
||||||
|
local dest = self.visible and config.plugins.todotreeview.treeview_size or 0
|
||||||
|
if self.init_size then
|
||||||
|
self.size.x = dest
|
||||||
|
self.init_size = false
|
||||||
|
else
|
||||||
|
self:move_towards(self.size, "x", dest)
|
||||||
|
end
|
||||||
|
|
||||||
|
TodoTreeView.super.update(self)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function TodoTreeView:draw()
|
||||||
|
self:draw_background(style.background2)
|
||||||
|
|
||||||
|
--local h = self:get_item_height()
|
||||||
|
local icon_width = style.icon_font:get_width("D")
|
||||||
|
local spacing = style.font:get_width(" ") * 2
|
||||||
|
local root_depth = 0
|
||||||
|
|
||||||
|
for item, x,y,w,h in self:each_item() do
|
||||||
|
local text_color = style.text
|
||||||
|
local tag_color = style.text
|
||||||
|
local file_color = config.plugins.todotreeview.todo_file_color.name or style.text
|
||||||
|
if config.plugins.todotreeview.tag_colors[item.tag] then
|
||||||
|
text_color = config.plugins.todotreeview.tag_colors[item.tag].text or style.text
|
||||||
|
tag_color = config.plugins.todotreeview.tag_colors[item.tag].tag or style.text
|
||||||
|
end
|
||||||
|
|
||||||
|
-- hovered item background
|
||||||
|
if item == self.hovered_item then
|
||||||
|
renderer.draw_rect(x, y, w, h, style.line_highlight)
|
||||||
|
text_color = style.accent
|
||||||
|
tag_color = style.accent
|
||||||
|
file_color = config.plugins.todotreeview.todo_file_color.hover or style.accent
|
||||||
|
if config.plugins.todotreeview.tag_colors[item.tag] then
|
||||||
|
text_color = config.plugins.todotreeview.tag_colors[item.tag].text_hover or style.accent
|
||||||
|
tag_color = config.plugins.todotreeview.tag_colors[item.tag].tag_hover or style.accent
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- icons
|
||||||
|
local item_depth = 0
|
||||||
|
x = x + (item_depth - root_depth) * style.padding.x + style.padding.x
|
||||||
|
if item.type == "file" then
|
||||||
|
local icon1 = item.expanded and "-" or "+"
|
||||||
|
common.draw_text(style.icon_font, file_color, icon1, nil, x, y, 0, h)
|
||||||
|
x = x + style.padding.x
|
||||||
|
common.draw_text(style.icon_font, file_color, "f", nil, x, y, 0, h)
|
||||||
|
x = x + icon_width
|
||||||
|
elseif item.type == "group" then
|
||||||
|
if config.plugins.todotreeview.todo_mode == "file_tag" then
|
||||||
|
x = x + style.padding.x * 0.75
|
||||||
|
end
|
||||||
|
|
||||||
|
if item.expanded then
|
||||||
|
common.draw_text(style.icon_font, tag_color, "-", nil, x, y, 0, h)
|
||||||
|
else
|
||||||
|
common.draw_text(icon_small_font, tag_color, ">", nil, x, y, 0, h)
|
||||||
|
end
|
||||||
|
x = x + icon_width / 2
|
||||||
|
else
|
||||||
|
if config.plugins.todotreeview.todo_mode == "tag" then
|
||||||
|
x = x + style.padding.x
|
||||||
|
else
|
||||||
|
x = x + style.padding.x * 1.5
|
||||||
|
end
|
||||||
|
common.draw_text(style.icon_font, text_color, "i", nil, x, y, 0, h)
|
||||||
|
x = x + icon_width
|
||||||
|
end
|
||||||
|
|
||||||
|
-- text
|
||||||
|
x = x + spacing
|
||||||
|
if item.type == "file" then
|
||||||
|
common.draw_text(style.font, file_color, item.filename, nil, x, y, 0, h)
|
||||||
|
elseif item.type == "group" then
|
||||||
|
common.draw_text(style.font, tag_color, item.tag, nil, x, y, 0, h)
|
||||||
|
else
|
||||||
|
if config.plugins.todotreeview.todo_mode == "file" then
|
||||||
|
common.draw_text(style.font, tag_color, item.tag, nil, x, y, 0, h)
|
||||||
|
x = x + style.font:get_width(item.tag)
|
||||||
|
common.draw_text(style.font, text_color, config.plugins.todotreeview.todo_separator..item.text, nil, x, y, 0, h)
|
||||||
|
else
|
||||||
|
common.draw_text(style.font, text_color, item.text, nil, x, y, 0, h)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function TodoTreeView:get_item_by_index(index)
|
||||||
|
local i = 0
|
||||||
|
for item in self:each_item() do
|
||||||
|
if index == i then
|
||||||
|
return item
|
||||||
|
end
|
||||||
|
i = i + 1
|
||||||
|
end
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
function TodoTreeView:get_hovered_parent_file_tag()
|
||||||
|
local file_parent = nil
|
||||||
|
local file_parent_index = 0
|
||||||
|
local group_parent = nil
|
||||||
|
local group_parent_index = 0
|
||||||
|
local i = 0
|
||||||
|
for item in self:each_item() do
|
||||||
|
if item.type == "file" then
|
||||||
|
file_parent = item
|
||||||
|
file_parent_index = i
|
||||||
|
end
|
||||||
|
if item.type == "group" then
|
||||||
|
group_parent = item
|
||||||
|
group_parent_index = i
|
||||||
|
end
|
||||||
|
if i == self.focus_index then
|
||||||
|
if item.type == "file" or item.type == "group" then
|
||||||
|
return file_parent, file_parent_index
|
||||||
|
else
|
||||||
|
return group_parent, group_parent_index
|
||||||
|
end
|
||||||
|
end
|
||||||
|
i = i + 1
|
||||||
|
end
|
||||||
|
return nil, 0
|
||||||
|
end
|
||||||
|
|
||||||
|
function TodoTreeView:get_hovered_parent()
|
||||||
|
local parent = nil
|
||||||
|
local parent_index = 0
|
||||||
|
local i = 0
|
||||||
|
for item in self:each_item() do
|
||||||
|
if item.type == "group" or item.type == "file" then
|
||||||
|
parent = item
|
||||||
|
parent_index = i
|
||||||
|
end
|
||||||
|
if i == self.focus_index then
|
||||||
|
return parent, parent_index
|
||||||
|
end
|
||||||
|
i = i + 1
|
||||||
|
end
|
||||||
|
return nil, 0
|
||||||
|
end
|
||||||
|
|
||||||
|
function TodoTreeView:update_scroll_position()
|
||||||
|
local h = self:get_item_height()
|
||||||
|
local _, min_y, _, max_y = self:get_content_bounds()
|
||||||
|
local start_row = math.floor(min_y / h)
|
||||||
|
local end_row = math.floor(max_y / h)
|
||||||
|
if self.focus_index < start_row then
|
||||||
|
self.scroll.to.y = self.focus_index * h
|
||||||
|
end
|
||||||
|
if self.focus_index + 1 > end_row then
|
||||||
|
self.scroll.to.y = (self.focus_index * h) - self.size.y + h
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- init
|
||||||
|
local view = TodoTreeView()
|
||||||
|
local node = core.root_view:get_active_node()
|
||||||
|
view.size.x = config.plugins.todotreeview.treeview_size
|
||||||
|
node:split("right", view, {x=true}, true)
|
||||||
|
|
||||||
|
core.status_view:add_item({
|
||||||
|
predicate = function()
|
||||||
|
return #view.filter > 0 and core.active_view and not core.active_view:is(CommandView)
|
||||||
|
end,
|
||||||
|
name = "todotreeview:filter",
|
||||||
|
alignment = core.status_view.Item.RIGHT,
|
||||||
|
get_item = function()
|
||||||
|
return {
|
||||||
|
style.text,
|
||||||
|
string.format("Filter: %s", view.filter)
|
||||||
|
}
|
||||||
|
end,
|
||||||
|
position = 1,
|
||||||
|
tooltip = "Todos filtered by",
|
||||||
|
separator = core.status_view.separator2
|
||||||
|
})
|
||||||
|
|
||||||
|
-- register commands and keymap
|
||||||
|
local previous_view = nil
|
||||||
|
command.add(nil, {
|
||||||
|
["todotreeview:toggle"] = function()
|
||||||
|
view.visible = not view.visible
|
||||||
|
end,
|
||||||
|
|
||||||
|
["todotreeview:expand-items"] = function()
|
||||||
|
for _, item in pairs(view.items) do
|
||||||
|
item.expanded = true
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
|
||||||
|
["todotreeview:hide-items"] = function()
|
||||||
|
for _, item in pairs(view.items) do
|
||||||
|
item.expanded = false
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
|
||||||
|
["todotreeview:toggle-focus"] = function()
|
||||||
|
if not core.active_view:is(TodoTreeView) then
|
||||||
|
previous_view = core.active_view
|
||||||
|
core.set_active_view(view)
|
||||||
|
view.hovered_item = view:get_item_by_index(view.focus_index)
|
||||||
|
else
|
||||||
|
command.perform("todotreeview:release-focus")
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
|
||||||
|
["todotreeview:filter-notes"] = function()
|
||||||
|
local todo_view_focus = core.active_view:is(TodoTreeView)
|
||||||
|
local previous_filter = view.filter
|
||||||
|
local submit = function(text)
|
||||||
|
view.filter = text
|
||||||
|
if todo_view_focus then
|
||||||
|
view.focus_index = 0
|
||||||
|
view.hovered_item = view:get_item_by_index(view.focus_index)
|
||||||
|
view:update_scroll_position()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
local suggest = function(text)
|
||||||
|
view.filter = text
|
||||||
|
end
|
||||||
|
local cancel = function(explicit)
|
||||||
|
view.filter = previous_filter
|
||||||
|
end
|
||||||
|
core.command_view:enter("Filter Notes", {
|
||||||
|
text = view.filter,
|
||||||
|
submit = submit,
|
||||||
|
suggest = suggest,
|
||||||
|
cancel = cancel
|
||||||
|
})
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
|
||||||
|
command.add(
|
||||||
|
function()
|
||||||
|
return core.active_view:is(TodoTreeView)
|
||||||
|
end, {
|
||||||
|
["todotreeview:previous"] = function()
|
||||||
|
if view.focus_index > 0 then
|
||||||
|
view.focus_index = view.focus_index - 1
|
||||||
|
view.hovered_item = view:get_item_by_index(view.focus_index)
|
||||||
|
view:update_scroll_position()
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
|
||||||
|
["todotreeview:next"] = function()
|
||||||
|
local next_index = view.focus_index + 1
|
||||||
|
local next_item = view:get_item_by_index(next_index)
|
||||||
|
if next_item then
|
||||||
|
view.focus_index = next_index
|
||||||
|
view.hovered_item = next_item
|
||||||
|
view:update_scroll_position()
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
|
||||||
|
["todotreeview:collapse"] = function()
|
||||||
|
if not view.hovered_item then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
if view.hovered_item.type == "file" then
|
||||||
|
view.hovered_item.expanded = false
|
||||||
|
else
|
||||||
|
if view.hovered_item.type == "group" and view.hovered_item.expanded then
|
||||||
|
view.hovered_item.expanded = false
|
||||||
|
else
|
||||||
|
if config.plugins.todotreeview.todo_mode == "file_tag" then
|
||||||
|
view.hovered_item, view.focus_index = view:get_hovered_parent_file_tag()
|
||||||
|
else
|
||||||
|
view.hovered_item, view.focus_index = view:get_hovered_parent()
|
||||||
|
end
|
||||||
|
|
||||||
|
view:update_scroll_position()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
|
||||||
|
["todotreeview:expand"] = function()
|
||||||
|
if not view.hovered_item then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
if view.hovered_item.type == "file" or view.hovered_item.type == "group" then
|
||||||
|
if view.hovered_item.expanded then
|
||||||
|
command.perform("todotreeview:next")
|
||||||
|
else
|
||||||
|
view.hovered_item.expanded = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
|
||||||
|
["todotreeview:open"] = function()
|
||||||
|
if not view.hovered_item then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
view:goto_hovered_item()
|
||||||
|
view.hovered_item = nil
|
||||||
|
end,
|
||||||
|
|
||||||
|
["todotreeview:release-focus"] = function()
|
||||||
|
core.set_active_view(
|
||||||
|
previous_view or core.root_view:get_primary_node().active_view
|
||||||
|
)
|
||||||
|
view.hovered_item = nil
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
|
||||||
|
keymap.add { ["ctrl+shift+t"] = "todotreeview:toggle" }
|
||||||
|
keymap.add { ["ctrl+shift+e"] = "todotreeview:expand-items" }
|
||||||
|
keymap.add { ["ctrl+shift+h"] = "todotreeview:hide-items" }
|
||||||
|
keymap.add { ["ctrl+shift+b"] = "todotreeview:filter-notes" }
|
||||||
|
keymap.add { ["up"] = "todotreeview:previous" }
|
||||||
|
keymap.add { ["down"] = "todotreeview:next" }
|
||||||
|
keymap.add { ["left"] = "todotreeview:collapse" }
|
||||||
|
keymap.add { ["right"] = "todotreeview:expand" }
|
||||||
|
keymap.add { ["return"] = "todotreeview:open" }
|
||||||
|
keymap.add { ["escape"] = "todotreeview:release-focus" }
|
||||||
|
|
Loading…
Reference in New Issue