more editor work

This commit is contained in:
kepler155c@gmail.com
2020-04-04 20:55:29 -06:00
parent f655cc5965
commit 0a7ec352cc
2 changed files with 136 additions and 95 deletions

View File

@@ -23,7 +23,6 @@ local mark = { }
local searchPattern local searchPattern
local undo = { chain = { }, pointer = 0 } local undo = { chain = { }, pointer = 0 }
local complete = { } local complete = { }
local page
h = h - 1 h = h - 1
@@ -116,28 +115,31 @@ local keyMapping = {
[ 'control-r' ] = 'refresh', [ 'control-r' ] = 'refresh',
} }
page = UI.Page { local page = UI.Page {
backgroundColor = color.panelColor, backgroundColor = color.panelColor,
menuBar = UI.MenuBar { menuBar = UI.MenuBar {
transitionHint = 'slideLeft', transitionHint = 'slideLeft',
buttons = { buttons = {
{ text = 'File', dropdown = { { text = 'File', dropdown = {
{ text = 'New ', event = 'menu_action', action = 'file_new' },
{ text = 'Open ', event = 'menu_action', action = 'file_open' },
{ spacer = true },
{ text = 'Save ^s', event = 'menu_action', action = 'save' }, { text = 'Save ^s', event = 'menu_action', action = 'save' },
{ text = 'Save As... ^S', event = 'menu_action', action = 'save_as', noFocus = true }, { text = 'Save As... ^S', event = 'menu_action', action = 'save_as' },
{ spacer = true }, { spacer = true },
{ text = 'Run', event = 'menu_action', action = 'run' }, { text = 'Run', event = 'menu_action', action = 'run' },
{ spacer = true }, { spacer = true },
{ text = 'Quit ^q', event = 'menu_action', action = 'exit', noFocus = true }, { text = 'Quit ^q', event = 'menu_action', action = 'exit' },
} }, } },
{ text = 'Edit', dropdown = { { text = 'Edit', dropdown = {
{ text = 'Cut ^x', event = 'menu_action', action = 'cut' }, { text = 'Cut ^x', event = 'menu_action', action = 'cut' },
{ text = 'Copy ^c', event = 'menu_action', action = 'copy' }, { text = 'Copy ^c', event = 'menu_action', action = 'copy' },
{ text = 'Paste ^V', event = 'menu_action', action = 'paste_internal' }, { text = 'Paste ^V', event = 'menu_action', action = 'paste_internal' },
{ spacer = true }, { spacer = true },
{ text = 'Find... ^f', event = 'menu_action', action = 'find_prompt', noFocus = true }, { text = 'Find... ^f', event = 'menu_action', action = 'find_prompt' },
{ text = 'Find Next ^n', event = 'menu_action', action = 'find_next' }, { text = 'Find Next ^n', event = 'menu_action', action = 'find_next' },
{ spacer = true }, { spacer = true },
{ text = 'Go to line... ^g', event = 'menu_action', action = 'goto_line', noFocus = true }, { text = 'Go to line... ^g', event = 'menu_action', action = 'goto_line' },
{ text = 'Mark all ^a', event = 'menu_action', action = 'mark_all' }, { text = 'Mark all ^a', event = 'menu_action', action = 'mark_all' },
} }, } },
}, },
@@ -172,10 +174,6 @@ page = UI.Page {
[ 'enter' ] = 'accept', [ 'enter' ] = 'accept',
}, },
}, },
disable = function(self)
UI.SlideOut.disable(self)
self:setFocus(page.editor)
end,
show = function(self) show = function(self)
self.lineNo:reset() self.lineNo:reset()
UI.SlideOut.show(self) UI.SlideOut.show(self)
@@ -217,10 +215,6 @@ page = UI.Page {
[ 'enter' ] = 'accept', [ 'enter' ] = 'accept',
}, },
}, },
disable = function(self)
UI.SlideOut.disable(self)
self:setFocus(page.editor)
end,
show = function(self) show = function(self)
self.search:markAll() self.search:markAll()
UI.SlideOut.show(self) UI.SlideOut.show(self)
@@ -267,10 +261,6 @@ page = UI.Page {
[ 'enter' ] = 'accept', [ 'enter' ] = 'accept',
}, },
}, },
disable = function(self)
UI.SlideOut.disable(self)
self:setFocus(page.editor)
end,
show = function(self) show = function(self)
self.filename.value = fileInfo.abspath self.filename.value = fileInfo.abspath
if self.filename.value then if self.filename.value then
@@ -283,7 +273,7 @@ page = UI.Page {
if event.type == 'accept' then if event.type == 'accept' then
local text = self.filename.value local text = self.filename.value
if text and #text > 0 then if text and #text > 0 then
actions.save(shell.resolve(text)) actions.save('/' .. text)
end end
self:hide() self:hide()
return true return true
@@ -291,7 +281,7 @@ page = UI.Page {
return UI.SlideOut.eventHandler(self, event) return UI.SlideOut.eventHandler(self, event)
end, end,
}, },
quit = UI.SlideOut { unsaved = UI.SlideOut {
x = -26, height = 1, y = -2, x = -26, height = 1, y = -2,
noFill = true, noFill = true,
close = UI.Button { close = UI.Button {
@@ -306,13 +296,13 @@ page = UI.Page {
x = 2, x = 2,
value = 'Save', value = 'Save',
}, },
save = UI.Button { yes = UI.Button {
x = 7, x = 7,
text = 'Yes', text = 'Yes',
backgroundColor = color.panelColor, backgroundColor = color.panelColor,
event = 'save_yes', event = 'save_yes',
}, },
quit = UI.Button { no = UI.Button {
x = 13, x = 13,
text = 'No', text = 'No',
backgroundColor = color.panelColor, backgroundColor = color.panelColor,
@@ -324,34 +314,52 @@ page = UI.Page {
backgroundColor = color.panelColor, backgroundColor = color.panelColor,
event = 'save_cancel', event = 'save_cancel',
}, },
disable = function(self) show = function(self, action)
UI.SlideOut.disable(self) self.action = action
self:setFocus(page.editor)
end,
show = function(self)
UI.SlideOut.show(self) UI.SlideOut.show(self)
self:addTransition('slideLeft', { easing = 'outBounce' }) self:addTransition('slideLeft', { easing = 'outBounce' })
end, end,
eventHandler = function(self, event) eventHandler = function(self, event)
if event.type == 'save_yes' then if event.type == 'save_yes' then
if actions.save() then if actions.save() then
UI:quit() self:hide()
actions.process(self.action)
end end
elseif event.type == 'save_no' then elseif event.type == 'save_no' then
UI:quit() actions.process(self.action, true)
self:hide()
elseif event.type == 'save_cancel' then elseif event.type == 'save_cancel' then
self:hide() self:hide()
end end
return UI.SlideOut.eventHandler(self, event) return UI.SlideOut.eventHandler(self, event)
end, end,
}, },
file_open = UI.FileSelect {
modal = true,
enable = function() end,
transitionHint = 'expandUp',
show = function(self)
UI.FileSelect.enable(self, fs.getDir(fileInfo.abspath))
self:focusFirst()
self:draw()
end,
eventHandler = function(self, event)
if event.type == 'select_cancel' then
self:disable()
elseif event.type == 'select_file' then
self:disable()
actions.process('open', event.file)
end
return UI.FileSelect.eventHandler(self, event)
end,
},
editor = UI.Window { editor = UI.Window {
y = 2, y = 2,
backgroundColor = colors.black, backgroundColor = colors.black,
transitionHint = 'slideRight', transitionHint = 'slideRight',
focus = function(self) focus = function(self)
if self.focused then if self.focused then
page.editor:setCursorPos(x - scrollX, y - scrollY) self:setCursorPos(x - scrollX, y - scrollY)
self:setCursorBlink(true) self:setCursorBlink(true)
else else
self:setCursorBlink(false) self:setCursorBlink(false)
@@ -380,6 +388,7 @@ page = UI.Page {
elseif ie.code == "mouse_click" or elseif ie.code == "mouse_click" or
ie.code == 'mouse_drag' or ie.code == 'mouse_drag' or
--ie.code == 'mouse_up' or --ie.code == 'mouse_up' or
ie.code == 'shift-mouse_click' or
ie.code == 'mouse_down' or ie.code == 'mouse_down' or
ie.code == 'mouse_doubleclick' then ie.code == 'mouse_doubleclick' then
@@ -405,14 +414,17 @@ page = UI.Page {
notification = UI.Notification { }, notification = UI.Notification { },
enable = function(self) enable = function(self)
UI.Page.enable(self) UI.Page.enable(self)
self:setFocus(page.editor) self:setFocus(self.editor)
end,
checkFocus = function(self)
if not self.focused or not self.focused.enabled then
-- if no current focus, set it to the editor
self:setFocus(self.editor)
end
end, end,
eventHandler = function(self, event) eventHandler = function(self, event)
if event.type == 'menu_action' then if event.type == 'menu_action' then
actions.process(event.element.action) actions.process(event.element.action)
if not event.element.noFocus then -- hacky
self:setFocus(self.editor)
end
return true return true
end end
return UI.Page.eventHandler(self, event) return UI.Page.eventHandler(self, event)
@@ -435,6 +447,10 @@ local function getFileInfo(path)
fi.isReadOnly = fs.isReadOnly(fi.abspath) fi.isReadOnly = fs.isReadOnly(fi.abspath)
end end
if multishell then
multishell.setTitle(multishell.getCurrent(), fs.getName(fi.path))
end
return fi return fi
end end
@@ -446,40 +462,6 @@ local function setError(pattern, ...)
page.notification:error(string.format(pattern, ...)) page.notification:error(string.format(pattern, ...))
end end
local function load(path)
fileInfo = getFileInfo(path)
tLines = {}
if fs.exists(fileInfo.abspath) then
local file = io.open(fileInfo.abspath, "r")
local sLine = file:read()
while sLine do
table.insert(tLines, sLine)
sLine = file:read()
end
file:close()
end
if #tLines == 0 then
table.insert(tLines, '')
end
local name = fileInfo.path
if fileInfo.isNew then
if not fileInfo.dirExists then
setStatus('"%s" [New DIRECTORY]', name)
else
setStatus('"%s" [New File]', name)
end
elseif fileInfo.isReadOnly then
setStatus('"%s" [readonly] %dL, %dC',
name, #tLines, fs.getSize(fileInfo.abspath))
else
setStatus('"%s" %dL, %dC',
name, #tLines, fs.getSize(fileInfo.abspath))
end
end
local function save( _sPath ) local function save( _sPath )
-- Create intervening folder -- Create intervening folder
local sDir = _sPath:sub(1, _sPath:len() - fs.getName(_sPath):len() ) local sDir = _sPath:sub(1, _sPath:len() - fs.getName(_sPath):len() )
@@ -758,6 +740,76 @@ actions = {
page.search:show() page.search:show()
end, end,
file_open = function(force)
if not force and undo.chain[#undo.chain] ~= lastSave then
page.unsaved:show('file_open')
else
page.file_open:show('file_open')
end
end,
file_new = function(force)
if not force and undo.chain[#undo.chain] ~= lastSave then
page.unsaved:show('file_new')
else
actions.open('/untitled.txt')
end
end,
open = function(filename)
if not actions.load(filename) then
setError('Unable to load file')
end
end,
load = function(path)
if fs.exists(path) and fs.isDir(path) then
return false
end
fileInfo = getFileInfo(path)
x, y = 1, 1
scrollX, scrollY = 0, 0
lastPos = { x = 1, y = 1 }
lastSave = nil
dirty = { y = 1, ey = h }
mark = { }
undo = { chain = { }, pointer = 0 }
complete = { }
tLines = { }
if fs.exists(fileInfo.abspath) then
local file = io.open(fileInfo.abspath, "r")
local sLine = file:read()
while sLine do
table.insert(tLines, sLine)
sLine = file:read()
end
file:close()
end
if #tLines == 0 then
table.insert(tLines, '')
end
local name = fileInfo.path
if fileInfo.isNew then
if not fileInfo.dirExists then
setStatus('"%s" [New DIRECTORY]', name)
else
setStatus('"%s" [New File]', name)
end
elseif fileInfo.isReadOnly then
setStatus('"%s" [readonly] %dL, %dC',
name, #tLines, fs.getSize(fileInfo.abspath))
else
setStatus('"%s" %dL, %dC',
name, #tLines, fs.getSize(fileInfo.abspath))
end
return true
end,
save = function(filename) save = function(filename)
filename = filename or fileInfo.abspath filename = filename or fileInfo.abspath
if fs.isReadOnly(filename) then if fs.isReadOnly(filename) then
@@ -767,9 +819,6 @@ actions = {
if ok then if ok then
lastSave = undo.chain[#undo.chain] lastSave = undo.chain[#undo.chain]
fileInfo = getFileInfo(filename) fileInfo = getFileInfo(filename)
if multishell then
multishell.setTitle(multishell.getCurrent(), fileInfo.path)
end
setStatus('"%s" %dL, %dC written', setStatus('"%s" %dL, %dC written',
fileInfo.path, #tLines, fs.getSize(fileInfo.abspath)) fileInfo.path, #tLines, fs.getSize(fileInfo.abspath))
return true return true
@@ -783,9 +832,9 @@ actions = {
page.save_as:show() page.save_as:show()
end, end,
exit = function() exit = function(force)
if undo.chain[#undo.chain] ~= lastSave then if not force and undo.chain[#undo.chain] ~= lastSave then
page.quit:show() page.unsaved:show('exit')
else else
UI:quit() UI:quit()
end end
@@ -810,12 +859,9 @@ actions = {
end, end,
status = function() status = function()
local modified = '' local modified = undo.chain[#undo.chain] == lastSave and '' or '[Modified] '
if undo.chain[1] then
modified = '[Modified] '
end
setStatus('"%s" %s%d lines --%d%%--', setStatus('"%s" %s%d lines --%d%%--',
fileInfo.path, modified, #tLines, fileInfo.abspath, modified, #tLines,
math.floor((y - 1) / (#tLines - 1) * 100)) math.floor((y - 1) / (#tLines - 1) * 100))
end, end,
@@ -1299,23 +1345,10 @@ actions = {
end, end,
} }
local tArgs = { ... } local args = { ... }
if #tArgs == 0 then if not actions.load(args[1] and args[1] or 'untitled.txt') then
error( "Usage: edit <path>" ) error('Error opening file')
end
-- Error checking
local sPath = shell.resolve(tArgs[1])
if fs.exists(sPath) and fs.isDir(sPath) then
error( "Cannot edit a directory." )
end
load(tArgs[1])
if multishell then
multishell.setTitle(multishell.getCurrent(), fs.getName(sPath))
end end
UI:setPage(page) UI:setPage(page)
UI:start() UI:start()

View File

@@ -65,4 +65,12 @@
run = "SoundPlayer", run = "SoundPlayer",
iconExt = "\030 \031 \128\0307\159\129\030 \0317\149\0310\144\0300\031 \155\030 \0310\137\144\010\0307\0317\128\128\128\030 \149\0300\031 \149\030 \128\0310\149\0300\031 \149\010\030 \031 \128\0317\130\0307\031 \144\030 \0317\149\0310\129\134\152\129", iconExt = "\030 \031 \128\0307\159\129\030 \0317\149\0310\144\0300\031 \155\030 \0310\137\144\010\0307\0317\128\128\128\030 \149\0300\031 \149\030 \128\0310\149\0300\031 \149\010\030 \031 \128\0317\130\0307\031 \144\030 \0317\149\0310\129\134\152\129",
}, },
[ "464c4ffd019e1e9691dcf0537c797353ef2b1c1d4833d3d463e5b74ae4547344" ] = {
title = "Editor",
category = "Apps",
run = "edit",
iconExt = "7\
¨¨¨¨f€0¨\
¨¨f€0¨¨f€",
}
} }