luaforwindows/SciTE/scite-debug/scite_lua/prompt.lua

304 lines
6.7 KiB
Lua
Executable File

--creating an Interactive Lua prompt
------------------------------- Lua prompt -----------------------
scite_require 'switch_buffers.lua'
scite_Command 'Start Interactive Lua|start_lua_prompt'
scite_Command 'Load Lua into Session|load_current_lua_file'
local lua_p
local skipping
local lua_interactive
local SL_prefix='\01SL\02'
function OnExit(s)
s = tonumber(s)
if s ~= 0 then
scite.MenuCommand(IDM_NEXTMSG)
end
end
local function write_to_lua(line,skip_output)
skipping = skip_output
lua_p:write(line..'\n')
end
function eval_lua(line)
local f,err = loadstring(line,'local')
if not f then
scite_Trace(err)
else
pcall(f)
end
end
function write_output(s)
if not skipping then
local i1,i2 = s:find(SL_prefix)
if i1 == 1 then
eval_lua(s:sub(i2+1))
else
scite_Trace(s)
end
else
skipping = false
end
end
function edit (f)
scite.Open(f)
end
-- the cd() command is special, because it is evaluated both in the Lua session _and_ in SciTE.
-- (cmd type 3s are evaluated in both contexts)
function cd (path)
if path then
os.chdir(path)
end
end
local cmds = {
cd = 3, dir = 1, edit = 2
}
local function check_command (line)
local cmd,rest = line:match('([%w_]+)(.*)')
local ctype = cmds[cmd]
if ctype then
local arg = rest:match('(%S+)')
if arg then
return cmd..'[['..arg..']]', ctype
else
return cmd..'()',ctype
end
else
return line,1
end
end
-- whenever SciTE changes its current directory, make sure that the prompt and SciTE are in sync!
scite_OnDirChange(function(dir)
if lua_p then
write_to_lua(('cd(%q)'):format(dir),true)
cd(dir)
end
end)
function evaluate_line(line)
line,ct = check_command (line)
if line == 'quit' then
if lua_interactive then
write_to_lua 'os.exit()'
else
write_to_lua 'quit'
end
print 'goodbye!'
scite.MenuCommand(IDM_WRAPOUTPUT)
lua_p = nil
return true
end
if ct == 2 or ct == 3 then
eval_lua(line)
if ct == 2 then scite_Trace '> ' end
end
if ct == 1 or ct == 3 then
write_to_lua(line)
end
end
function start_lua_prompt()
if lua_p ~= nil then return end
local cmd = props['lua.prompt']
lua_interactive = cmd:find('-i',1,true)
scite.MenuCommand(IDM_WRAPOUTPUT)
lua_p = spawner.new(cmd)
lua_p:set_output('write_output')
lua_p:run()
scite_InteractivePromptHandler('>+ ',evaluate_line)
end
function load_current_lua_file()
if lua_p then
scite.MenuCommand(IDM_SAVE)
write_to_lua('print(pcall(dofile,[['..props['FilePath']..']]))',true)
scite.MenuCommand(IDM_SWITCHPANE)
end
end
--- a general interactive prompt engine -----
local keymap
local lines
local lines_idx = 1
local line_callback
local prompt
local lastpos = 1
if not GTK then -- see winuser.h
keymap = {
[40] = SCK_DOWN,
[38] = SCK_UP,
[37] = SCK_LEFT,
[39] = SCK_RIGHT,
[36] = SCK_HOME,
[35] = SCK_END,
[33] = SCK_PRIOR,
[34] = SCK_NEXT,
[46] = SCK_DELETE,
[45] = SCK_INSERT,
[0x1B] = SCK_ESCAPE,
[8] = SCK_BACK,
[9] = SCK_TAB,
[13] = SCK_RETURN,
[0x6B] = SCK_ADD,
[0x6D] = SCK_SUBTRACT,
[0x6F] = SCK_DIVIDE,
[0x5B] = SCK_WIN,
[0x5C] = SCK_RWIN,
[18] = SCK_MENU,
}
else -- see gdk/gdkkeysyms.h
keymap = {
[0xFF54] = SCK_DOWN,
[0xFF52] = SCK_UP,
[0xFF51] = SCK_LEFT,
[0xFF53] = SCK_RIGHT,
[0xFF50] = SCK_HOME,
[0xFF57] = SCK_END,
[0xFF55] = SCK_PRIOR,
[0xFF56] = SCK_NEXT,
[0xFFFF] = SCK_DELETE,
[0xFF63] = SCK_INSERT,
[0xFF1B] = SCK_ESCAPE,
[0xFF08] = SCK_BACK,
[0xFF09] = SCK_TAB,
[0xFF0D] = SCK_RETURN,
[0xFFAB] = SCK_ADD,
[0xFFAD] = SCK_SUBTRACT,
[0xFFAF] = SCK_DIVIDE,
[0xFFEB] = SCK_WIN,
[0xFFEC] = SCK_RWIN,
[0xFF67] = SCK_MENU,
}
end
function scite_ConvertToSCK (key)
local res = keymap[key]
if res then return res else return key end
end
function enable_arrow_keys (yesno)
if yesno then
output:AssignCmdKey(SCK_TAB,0,SCI_TAB)
output:AssignCmdKey(SCK_UP,0,SCI_LINEUP)
output:AssignCmdKey(SCK_DOWN,0,SCI_LINEDOWN)
else
output:AssignCmdKey(SCK_TAB,0,SCI_NULL)
output:AssignCmdKey(SCK_UP,0,SCI_NULL)
output:AssignCmdKey(SCK_DOWN,0,SCI_NULL)
end
end
function scite_ReplaceLine(pane,l,txt)
pane.TargetStart = lastpos --pane:PositionFromLine(l)
pane.TargetEnd = pane.LineEndPosition[l]
pane:ReplaceTarget(txt)
pane:GotoPos(pane.TargetEnd)
end
local function current_line ()
return output:LineFromPosition(output.CurrentPos)
end
function replace_current_line (txt)
local l = current_line()
--~ scite_ReplaceLine(output,l,prompt..txt)
scite_ReplaceLine(output,l,txt)
end
local function strip_prompt(line)
--~ local i1,i2 = line:find(prompt)
--~ if i1 == 1 then
--~ line = line:sub(i2+1)
--~ end
--~ return line
local l = current_line()-1
local p = output:PositionFromLine(l)
local offset = lastpos - p + 1
return line:sub(offset)
end
function handle_keys (key)
if editor.Focus then return end
key = scite_ConvertToSCK(key)
local delta
if key == SCK_UP then
if lines_idx == 1 then return end
delta = -1
elseif key == SCK_DOWN then
if lines_idx == #lines then return end
delta = 1
elseif key == SCK_TAB then
local line = strip_prompt(output:GetCurLine())
local matches = {}
for i,l in ipairs(lines) do
if l:find(line,1,true) == 1 then
table.insert(matches,1,l)
end
end
if #matches == 0 then return end
if #matches == 1 then
replace_current_line(matches[1])
return
end
enable_arrow_keys (true)
scite_UserListShow(matches,1,function(l)
replace_current_line(l)
enable_arrow_keys (false)
end)
return
end
if delta then
lines_idx = lines_idx + delta
local txt = lines[lines_idx]
if txt then
replace_current_line(txt)
end
end
end
function scite_Trace (s)
trace(s)
lastpos = output.CurrentPos
end
local function line_handler(line)
line = strip_prompt(line)
-- prevent immediate duplicates
if lines[#lines] ~= line then
table.insert(lines,line)
end
lines_idx = #lines + 1
if line_callback(line) then
scite_LeaveInteractivePrompt()
end
end
function scite_InteractivePromptHandler(the_prompt,fun)
prompt = the_prompt
line_callback = fun
lines_idx = 1
lines = {}
enable_arrow_keys(false)
scite_OnKey(handle_keys)
scite_OnOutputLine(line_handler)
end
function scite_LeaveInteractivePrompt ()
scite_OnOutputLine(line_handler,true)
enable_arrow_keys(true)
scite_OnKey(handle_keys,'remove')
end