410 lines
9.2 KiB
Lua
Executable File

require "CLRPackage"
require "ilua"
require "CLRForm"
import "System.Windows.Forms"
import "System.Drawing"
import "System.IO"
import "TextBox.dll"
local ferr = io.stderr --debug
local append = table.insert
-- it appears necessary to force a delayed evaluation, for which we use a timer....
local timer = Timer()
timer.Interval = 10
local callback
timer.Tick:Add(function()
timer:Stop()
callback()
end)
local function call_later (fun)
callback = fun
timer:Start()
end
local function readfile (file)
local f = io.open(file,'r')
if not f then return end
local res = f:read("*a")
f:close()
return res
end
local function writefile (file,s)
local f = io.open(file,'w')
if not f then return end
f:write(s)
f:close()
return true
end
function current_line (pane)
return pane:GetLineFromCharIndex(pane.SelectionStart)
end
-- a useful function for selecting lines in Rich text boxes; if lno is not specified,
-- then use the current line
function select_line (pane,lno)
if not lno then -- current line
lno = current_line(pane)
end
local istart = 0
local i = 0
for line in enum(pane.Lines) do
local len = #line
if i == lno then
pane:Select(istart,len)
return
end
i = i + 1
istart = istart + len + 1
end
end
local lines = {}
local list = ListBox()
local no_name = true
local this_dir = Environment.CurrentDirectory
local user_dir = Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory)
local session_dir = user_dir..'\\'..'li-session'
--ferr:write('session ',session_dir,'\n')
if Directory.Exists(session_dir) then
local files = Directory.GetFiles(session_dir,"*.lua")
for i = 1,files.Length do
list.Items:Add(Path.GetFileNameWithoutExtension(files[i-1]))
end
else
Directory.CreateDirectory(session_dir)
end
local function list_contains (name)
for i = 1,list.Items.Count do
if list.Items[i-1] == name then return true end
end
end
local function add_to_list (name)
list.Items:Add(name)
list.SelectedItem = name
current_name = name
end
local function session_file (name)
if not name then return end
return session_dir..'\\'..name..'.lua'
end
local code = ConsoleTextBox() --RichTextBox()
code.Font = Font("Tahoma",10,FontStyle.Bold)
code.WordWrap = false
code:SetHandler(function(key)
if key == Keys.Tab then
code.SelectedText = " "
return true
end
return false
end)
local text = ConsoleTextBox() --RichTextBox()
text.Font = code.Font
text.WordWrap = false
-- please note that you must explicitly return false, since LuaInterface is
-- expecting a boolean return value!
text:SetHandler(function(key)
if key == Keys.Up then
get_history(true)
return true
elseif key == Keys.Down then
get_history(false)
return true
end
return false
end)
local function write (s)
text:AppendText(s)
end
list.SelectedIndexChanged:Add(function()
local file = session_file(list.SelectedItem)
if not file or not File.Exists(file) then return end
local txt = readfile(file)
if not txt then
ShowError ("Cannot open '"..file.."'")
return
end
code.Text = txt
end)
local function load_lua_file (file)
local oldFun = fun
fun = function(file) end
local res,err = pcall(dofile,file)
if not res then -- we have an error!
ShowError(err)
print(err)
end
fun = oldFun
end
local function load_lua ()
local dlg = OpenFileDialog()
dlg.Filter = "Lua (*.lua)|*.lua"
dlg.InitialDirectory = this_dir
if dlg:ShowDialog() == DialogResult.OK then
load_lua_file(dlg.FileName)
end
end
local function save_session ()
local dlg = SaveFileDialog()
dlg.Filter = "Lua (*.lua)|*.lua"
dlg.InitialDirectory = this_dir
if dlg:ShowDialog() ~= DialogResult.OK then return end
local f = io.open(dlg.FileName,"w")
f:write(table.concat(lines,'\n'))
f:close()
end
function clear_code ()
code:Clear()
no_name = true
end
function delete_list_item ()
local path = session_file(list.SelectedItem)
os.remove(path)
list.Items:Remove(list.SelectedItem)
clear_code()
end
function save_code ()
local file
if code.Lines.Length == 0 then return end
if not no_name then
file = list.SelectedItem
else -- no name has been assigned, after clearing the code pane
-- try make up an appropriate one!
local firstline = code.Lines[0]
local comment = firstline:match('%s*%-%-%s*(.*)')
if comment then file = comment
else file = "[current]" end
no_name = false
end
local path = session_file(file)
writefile(path,code.Text)
if not list_contains(file) then
add_to_list(file)
else
list.SelectedItem = file
end
return path
end
local function save_text ()
local dlg = SaveFileDialog()
dlg.Filter = "Text (*.txt)|*.txt"
dlg.InitialDirectory = this_dir
if dlg:ShowDialog() ~= DialogResult.OK then return end
writefile(dlg.FileName,text.Text)
end
local function save_and_go ()
local file = save_code()
if not file then return end
local res,err = pcall(dofile,file)
--ferr:write(file,'\n')
if not res then
local i1,i2,line = err:find(':(%d+):')
if i1 then
print(err:sub(i2+1))
write '\n> '
code:Focus()
select_line(code,tonumber(line)-1)
return
end
end
write '\n> '
append(lines,'dofile[['..file..']]')
text:Focus()
end
function fun (fn)
if not fn then -- prompt for a function name
fn = PromptForString("Lua Interface Console","Function name","")
if not fn then return end
end
if list_contains(fn) then
ShowError("'"..fn.."' already exists. Pick another name")
return
end
no_name = false
local txt = "function "..fn.."( )\n\nend\n"
code.Text = txt
add_to_list(fn)
code:Focus()
end
---------------------- Main Menu --------------------------------------
local menu = main_menu {
"File",{
"Load Lua(CtrlO)",load_lua,
"Save Session(CtrlS)",save_session,
"Save As Text",save_text,
"E&xit(CtrlX)",function() os.exit(0) end,
},
"Run",{
"Save and Go(F5)",save_and_go,
"Create Function",function() fun() end,
"Delete Item",delete_list_item,
"Clear Code Pane",clear_code,
},
"History", {
"Last(AltUpArrow)", function() get_history(true) end,
"Previous(AltDownArrow)", function() get_history(false) end
}
}
local function method (obj,fun)
return function()
fun(obj)
end
end
local popup = popup_menu {
"Copy",method(text,text.Copy),
"Paste",method(text,text.Paste),
"Cut",method(text,text.Cut),
}
------------ Managing Command History -----------
local help_idx = 1
function get_history (up)
call_later(function()
local delta
-- awful hack, cancelling out the last up/down arrow movement!
if up then
delta = -1
else
delta = 1
end
key_sent = true
call_later(function()
help_idx = help_idx + delta
local txt = lines[help_idx]
if not txt then
help_idx = help_idx - delta
return
end
select_line(text)
text.SelectedText = '> '..txt
end)
end)
end
------------ Special Key Handling ------------------
local lastLine = -1
text.KeyDown:Add(function(sender,args)
if args.KeyCode == Keys.Enter then
local lineNo = text:GetLineFromCharIndex(text.SelectionStart)
if lineNo ~= lastLine then -- for some reason, happens twice!
local line = text.Lines[lineNo]
line = line:gsub('^> ','')
lastLine = lineNo
call_later(function()
eval_lua(line)
append(lines,line)
help_idx = #lines + 1
write '> '
end)
end
end
end)
----------------------- Ouput Redirection ---------------------------------
function write_out (expand,...)
local t = {...}
local n = #t - 1
for i = 1,n do
write(tostring(t[i]))
if expand then write '\t' end
end
write(tostring(t[n+1]))
end
function writer (...)
write_out(false,...)
end
ilua.set_writer(writer)
function print (...)
write_out(true,...)
write '\r\n'
end
-------- Layout Controls ---------------------------------------------
local form = Form()
form.Menu = menu
form.Text = "LuaInterface GUI Prompt"
form.Size = Size(420,420)
form.Closing:Add(function()
os.exit(0)
end)
local panel = Panel()
panel.Dock = DockStyle.Top
local hsplitter = Splitter()
hsplitter.Dock = DockStyle.Left
hsplitter.MinSize = 70
code.Dock = DockStyle.Fill
code.Height = 70
list.Dock = DockStyle.Left
list.Width = 70
panel.Controls:Add(code)
panel.Controls:Add(hsplitter)
panel.Controls:Add(list)
-- note the particular order!
local splitter = Splitter()
splitter.Dock = DockStyle.Top
splitter.MinSize = 70
splitter.MinExtra = 100
text.Dock = DockStyle.Fill
text.ContextMenu = popup
form.Controls:Add(text)
form.Controls:Add(splitter)
form.Controls:Add(panel)
-- stuff exported to the interactive console
gettype = luanet.import_type
app = {code=code,text=text, list=list, form=form}
function cd (path)
if not path or #path == 0 then
print(Directory.GetCurrentDirectory())
else
Directory.SetCurrentDirectory(path)
end
end
write 'ILUA: Lua 5.1.1 Copyright (C) 1994-2007 Lua.org, PUC-Rio\r\n'
write '> '
if arg[1] and File.Exists(arg[1]) then
load_lua_file(arg[1])
end
form:ShowDialog()