410 lines
9.2 KiB
Lua
Executable File
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()
|
|
|
|
|