2022-07-26 17:04:07 +00:00
|
|
|
Recently_modified_lookback_window = 10
|
|
|
|
|
2022-07-28 04:29:41 +00:00
|
|
|
Commands = {
|
2022-07-29 05:23:35 +00:00
|
|
|
'capture', -- hard-coded at index 1; we want C-enter enter to create a new note
|
2022-07-28 04:33:45 +00:00
|
|
|
'edit note at cursor (ctrl+e)', -- hard-coded at index 2; see candidates() below
|
2022-07-29 05:08:59 +00:00
|
|
|
'maximize note', -- hard-coded at index 3; see candidates() below
|
2022-07-28 04:29:41 +00:00
|
|
|
'close column surrounding cursor',
|
|
|
|
'recently modified',
|
|
|
|
'reload note at cursor from disk',
|
|
|
|
'search (all notes)',
|
|
|
|
'/ (find on screen)',
|
|
|
|
}
|
|
|
|
|
2022-07-24 04:00:49 +00:00
|
|
|
function handle_command_palette_keychord(chord, key)
|
|
|
|
if chord == 'escape' then
|
2022-07-29 03:36:39 +00:00
|
|
|
Display_settings.show_palette = false
|
2022-07-27 17:01:32 +00:00
|
|
|
-- don't forget text in case we want to continue it
|
2022-07-24 04:00:49 +00:00
|
|
|
elseif chord == 'backspace' then
|
|
|
|
local len = utf8.len(Display_settings.palette)
|
|
|
|
local byte_offset = Text.offset(Display_settings.palette, len)
|
|
|
|
Display_settings.palette = string.sub(Display_settings.palette, 1, byte_offset-1)
|
|
|
|
Display_settings.palette_text = App.newText(love.graphics.getFont(), Display_settings.palette)
|
2022-07-24 05:21:00 +00:00
|
|
|
elseif chord == 'tab' then
|
|
|
|
-- select top candidate, but don't submit
|
|
|
|
local candidates = candidates()
|
|
|
|
Display_settings.palette = candidates[1]:gsub(' %(.*', '')
|
|
|
|
Display_settings.palette_text = App.newText(love.graphics.getFont(), Display_settings.palette)
|
2022-07-24 04:00:49 +00:00
|
|
|
elseif chord == 'return' then
|
2022-07-24 05:21:00 +00:00
|
|
|
-- select top candidate and submit
|
2022-07-24 04:00:49 +00:00
|
|
|
-- TODO: handle search command
|
|
|
|
local candidates = candidates()
|
|
|
|
if #candidates > 0 then
|
2022-07-29 18:32:53 +00:00
|
|
|
if file_exists(Directory..candidates[1]) then
|
2022-07-24 07:08:52 +00:00
|
|
|
command.open_file(candidates[1])
|
2022-07-24 04:26:35 +00:00
|
|
|
else
|
2022-07-24 07:08:52 +00:00
|
|
|
local function_name = candidates[1]:gsub(' %(.*', ''):gsub('%W', '_')
|
|
|
|
local fn = command[function_name]
|
|
|
|
if fn then
|
|
|
|
fn()
|
|
|
|
else
|
|
|
|
print(('not implemented yet: %s'):format(function_name))
|
|
|
|
end
|
2022-07-24 04:26:35 +00:00
|
|
|
end
|
2022-07-24 04:00:49 +00:00
|
|
|
end
|
2022-07-27 17:01:32 +00:00
|
|
|
-- forget text for next command
|
2022-07-29 03:33:45 +00:00
|
|
|
Display_settings.palette = ''
|
|
|
|
Display_settings.palette_text = App.newText(love.graphics.getFont(), '')
|
2022-07-27 17:01:32 +00:00
|
|
|
--
|
2022-07-29 03:36:39 +00:00
|
|
|
Display_settings.show_palette = false
|
2022-07-24 04:00:49 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
function draw_command_palette()
|
|
|
|
local pwidth,pheight = 400, 300
|
|
|
|
local left = math.max(App.screen.width/2-pwidth/2, 0)
|
|
|
|
local top = math.max(App.screen.height/2-pheight/2, 0)
|
|
|
|
local width = math.min(pwidth, App.screen.width)
|
|
|
|
local height = math.min(pheight, App.screen.height)
|
|
|
|
-- background
|
|
|
|
App.color(Command_palette_background_color)
|
|
|
|
love.graphics.rectangle('fill', left, top, width, height, 10, 10) -- rounded corners
|
|
|
|
App.color(Command_palette_border_color)
|
|
|
|
love.graphics.rectangle('line', left, top, width, height, 10, 10) -- rounded corners
|
|
|
|
love.graphics.line(left, top+5+Line_height+5, left+width, top+5+Line_height+5)
|
|
|
|
-- input box
|
|
|
|
App.color(Command_palette_command_color)
|
|
|
|
draw_palette_input(left+10, top+5)
|
|
|
|
-- alternatives
|
|
|
|
App.color(Command_palette_alternatives_color)
|
|
|
|
local y = top+5+Line_height+5+5
|
|
|
|
for _,cmd in ipairs(candidates()) do
|
|
|
|
love.graphics.print(cmd, left+5,y)
|
|
|
|
y = y+Line_height
|
|
|
|
if y >= top+height then
|
|
|
|
break
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
function draw_palette_input(x, y)
|
|
|
|
love.graphics.draw(Display_settings.palette_text, x,y)
|
|
|
|
x = x+App.width(Display_settings.palette_text)
|
|
|
|
draw_cursor(x, y)
|
|
|
|
end
|
|
|
|
|
|
|
|
function draw_cursor(x, y)
|
|
|
|
-- blink every 0.5s
|
|
|
|
if math.floor(Cursor_time*2)%2 == 0 then
|
|
|
|
App.color(Cursor_color)
|
|
|
|
love.graphics.rectangle('fill', x,y, 3,Line_height)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
function candidates()
|
2022-07-29 05:08:59 +00:00
|
|
|
-- slight context-sensitive tweaks
|
|
|
|
if Display_settings.mode == 'normal' then
|
|
|
|
Commands[3] = 'maximize note'
|
|
|
|
else
|
|
|
|
Commands[3] = 'back to surface'
|
|
|
|
end
|
2022-07-28 04:33:45 +00:00
|
|
|
local pane = Surface[Cursor_pane.col][Cursor_pane.row]
|
|
|
|
if pane.show_cursor then
|
|
|
|
Commands[2] = 'exit editing (ctrl+e)'
|
|
|
|
else
|
|
|
|
Commands[2] = 'edit note at cursor (ctrl+e)'
|
|
|
|
end
|
|
|
|
--
|
2022-07-24 04:00:49 +00:00
|
|
|
if Display_settings.palette == '' then
|
|
|
|
return Commands
|
|
|
|
elseif Display_settings.palette:sub(1,1) == '/' then
|
|
|
|
return {}
|
|
|
|
else
|
|
|
|
local results = filter_candidates(Commands, Display_settings.palette)
|
|
|
|
append(results, file_candidates(Display_settings.palette))
|
|
|
|
return results
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
function filter_candidates(candidates, prefix)
|
|
|
|
local result = {}
|
|
|
|
for _,cand in ipairs(candidates) do
|
2022-07-27 01:27:18 +00:00
|
|
|
if cand:find(prefix, 1, --[[literal pattern]] true) == 1 then
|
2022-07-24 04:00:49 +00:00
|
|
|
table.insert(result, cand)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
return result
|
|
|
|
end
|
|
|
|
|
|
|
|
function file_candidates(prefix)
|
2022-07-27 01:05:48 +00:00
|
|
|
if love.filesystem.getInfo(Directory..prefix, 'file') then
|
|
|
|
return {prefix}
|
|
|
|
end
|
2022-07-24 06:27:44 +00:00
|
|
|
local path = Directory
|
2022-07-24 05:17:41 +00:00
|
|
|
local visible_dir = ''
|
|
|
|
if prefix:find('/') then
|
|
|
|
visible_dir = dirname(prefix)
|
|
|
|
path = path..dirname(prefix)
|
2022-07-24 04:00:49 +00:00
|
|
|
end
|
|
|
|
local files = love.filesystem.getDirectoryItems(path)
|
|
|
|
local base = basename(prefix)
|
|
|
|
return concat_all(visible_dir, filter_candidates(reorder(path, files), base))
|
|
|
|
end
|
|
|
|
|
|
|
|
function reorder(dir, files)
|
|
|
|
local result = {}
|
|
|
|
local info = {}
|
|
|
|
for _,file in ipairs(files) do
|
|
|
|
info[file] = love.filesystem.getInfo(dir..'/'..file)
|
|
|
|
end
|
|
|
|
-- files before directories
|
|
|
|
for _,file in ipairs(files) do
|
|
|
|
if info[file].type ~= 'directory' then
|
|
|
|
table.insert(result, file)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
for _,file in ipairs(files) do
|
|
|
|
if info[file].type == 'directory' then
|
|
|
|
table.insert(result, file..'/')
|
|
|
|
end
|
|
|
|
end
|
|
|
|
return result
|
|
|
|
end
|
2022-07-24 04:26:35 +00:00
|
|
|
|
|
|
|
command = {}
|
|
|
|
|
2022-07-29 05:23:35 +00:00
|
|
|
function command.capture()
|
2022-07-24 04:26:35 +00:00
|
|
|
local filename = os.date('%Y/%m/%d/%H-%M-%S')
|
2022-07-26 19:04:20 +00:00
|
|
|
print('creating directory '..Directory..dirname(filename))
|
2022-07-24 06:27:44 +00:00
|
|
|
local status = love.filesystem.createDirectory(Directory..dirname(filename))
|
2022-07-24 04:26:35 +00:00
|
|
|
assert(status)
|
|
|
|
Cache[filename] = {lines={{mode='text', data=''}}, left=0, right=Display_settings.column_width}
|
2022-07-26 06:40:09 +00:00
|
|
|
initialize_file_metadata(Cache[filename])
|
2022-07-24 04:26:35 +00:00
|
|
|
local column = {name=filename}
|
2022-07-26 06:42:03 +00:00
|
|
|
local pane = load_pane_from_file(filename)
|
2022-07-24 04:26:35 +00:00
|
|
|
table.insert(column, pane)
|
|
|
|
table.insert(Surface, Cursor_pane.col+1, column)
|
|
|
|
Cursor_pane.col = Cursor_pane.col+1
|
|
|
|
Cursor_pane.row = 1
|
2022-07-24 05:01:13 +00:00
|
|
|
local col_sx = left_edge_sx(Cursor_pane.col)
|
|
|
|
if col_sx > Display_settings.x + App.screen.width - Display_settings.column_width then
|
|
|
|
Display_settings.x = math.max(0, col_sx + Display_settings.column_width + Margin_right + Padding_horizontal - App.screen.width)
|
|
|
|
Display_settings.y = 0
|
|
|
|
end
|
2022-07-24 04:26:35 +00:00
|
|
|
stop_editing_all()
|
|
|
|
pane.show_cursor = true
|
2022-07-29 05:23:35 +00:00
|
|
|
Display_settings.mode = 'maximize'
|
2022-07-24 04:26:35 +00:00
|
|
|
end
|
2022-07-24 04:37:24 +00:00
|
|
|
|
2022-07-29 05:08:59 +00:00
|
|
|
function command.maximize_note()
|
2022-07-29 04:58:46 +00:00
|
|
|
Display_settings.mode = 'maximize'
|
|
|
|
end
|
|
|
|
|
2022-07-29 05:08:59 +00:00
|
|
|
function command.back_to_surface()
|
|
|
|
Display_settings.mode = 'normal'
|
2022-07-29 05:23:35 +00:00
|
|
|
update_pane_bounds()
|
2022-07-29 05:08:59 +00:00
|
|
|
end
|
|
|
|
|
2022-07-24 04:37:24 +00:00
|
|
|
function command.close_column_surrounding_cursor()
|
|
|
|
stop_editing_all()
|
|
|
|
table.remove(Surface, Cursor_pane.col)
|
|
|
|
if Cursor_pane.col > 1 then
|
|
|
|
Cursor_pane.col = Cursor_pane.col - 1
|
|
|
|
Cursor_pane.row = 1
|
2022-07-24 05:01:13 +00:00
|
|
|
local col_sx = left_edge_sx(Cursor_pane.col)
|
|
|
|
if col_sx + Display_settings.column_width < Display_settings.x then
|
|
|
|
Display_settings.x = col_sx - Margin_left - Padding_horizontal
|
|
|
|
end
|
2022-07-24 04:37:24 +00:00
|
|
|
end
|
|
|
|
end
|
2022-07-24 04:39:30 +00:00
|
|
|
|
|
|
|
function command.edit_note_at_cursor()
|
|
|
|
local pane = Surface[Cursor_pane.col][Cursor_pane.row]
|
2022-07-29 04:55:01 +00:00
|
|
|
assert(not pane.show_cursor)
|
|
|
|
stop_editing_all()
|
|
|
|
pane.recent_updated = false
|
|
|
|
pane.show_cursor = true
|
|
|
|
end
|
|
|
|
|
|
|
|
function command.exit_editing()
|
|
|
|
local pane = Surface[Cursor_pane.col][Cursor_pane.row]
|
|
|
|
assert(pane.show_cursor)
|
|
|
|
stop_editing(pane)
|
2022-07-24 04:39:30 +00:00
|
|
|
end
|
2022-07-24 05:38:19 +00:00
|
|
|
|
|
|
|
function command.recently_modified()
|
2022-07-26 17:02:27 +00:00
|
|
|
local filenames = {}
|
2022-07-24 06:27:44 +00:00
|
|
|
for line in love.filesystem.lines(Directory..'recent') do
|
2022-07-26 17:02:27 +00:00
|
|
|
table.insert(filenames, line)
|
2022-07-24 05:38:19 +00:00
|
|
|
end
|
2022-07-26 17:04:07 +00:00
|
|
|
local done, ndone = {}, 0
|
2022-07-24 05:38:19 +00:00
|
|
|
local column = {name='recently modified'}
|
2022-07-26 17:02:27 +00:00
|
|
|
for i=#filenames,1,-1 do
|
|
|
|
local filename = filenames[i]
|
2022-07-26 17:04:07 +00:00
|
|
|
if ndone >= Recently_modified_lookback_window then break end
|
2022-07-24 05:38:19 +00:00
|
|
|
if not done[filename] then
|
|
|
|
done[filename] = true
|
2022-07-26 17:04:07 +00:00
|
|
|
ndone = ndone+1
|
2022-07-24 06:23:59 +00:00
|
|
|
--? print('loading', filename)
|
|
|
|
local pane = load_pane_from_file(filename)
|
2022-07-24 05:38:19 +00:00
|
|
|
table.insert(column, pane)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
table.insert(Surface, Cursor_pane.col+1, column)
|
2022-07-24 06:23:59 +00:00
|
|
|
Cursor_pane.col = Cursor_pane.col+1
|
2022-07-24 05:38:19 +00:00
|
|
|
Cursor_pane.row = 1
|
|
|
|
local col_sx = left_edge_sx(Cursor_pane.col)
|
|
|
|
if col_sx > Display_settings.x + App.screen.width - Display_settings.column_width then
|
|
|
|
Display_settings.x = math.max(0, col_sx + Display_settings.column_width + Margin_right + Padding_horizontal - App.screen.width)
|
|
|
|
Display_settings.y = 0
|
|
|
|
end
|
|
|
|
end
|
2022-07-24 07:08:52 +00:00
|
|
|
|
|
|
|
function command.open_file(filename)
|
|
|
|
local column = {name=filename}
|
|
|
|
local pane = load_pane_from_file(filename)
|
|
|
|
table.insert(column, pane)
|
|
|
|
table.insert(Surface, Cursor_pane.col+1, column)
|
|
|
|
Cursor_pane.col = Cursor_pane.col+1
|
|
|
|
Cursor_pane.row = 1
|
|
|
|
local col_sx = left_edge_sx(Cursor_pane.col)
|
|
|
|
if col_sx > Display_settings.x + App.screen.width - Display_settings.column_width then
|
|
|
|
Display_settings.x = math.max(0, col_sx + Display_settings.column_width + Margin_right + Padding_horizontal - App.screen.width)
|
|
|
|
Display_settings.y = 0
|
|
|
|
end
|
2022-07-29 05:23:35 +00:00
|
|
|
update_pane_bounds()
|
2022-07-24 07:08:52 +00:00
|
|
|
end
|