883 lines
22 KiB
Lua
Executable File
883 lines
22 KiB
Lua
Executable File
-- Extman is a Lua script manager for SciTE. It enables multiple scripts to capture standard events
|
||
-- without interfering with each other. For instance, scite_OnDoubleClick() will register handlers
|
||
-- for scripts that need to know when a double-click event has happened. (To know whether it
|
||
-- was in the output or editor pane, just test editor.Focus). It provides a useful function scite_Command
|
||
-- which allows you to define new commands without messing around with property files (see the
|
||
-- examples in the scite_lua directory.)
|
||
-- extman defines three new convenience handlers as well:
|
||
--scite_OnWord (called when user has entered a word)
|
||
--scite_OnEditorLine (called when a line is entered into the editor)
|
||
--scite_OnOutputLine (called when a line is entered into the output pane)
|
||
|
||
-- this is an opportunity for you to make regular Lua packages available to SciTE
|
||
--~ package.path = package.path..';C:\\lang\\lua\\lua\\?.lua'
|
||
--~ package.cpath = package.cpath..';c:\\lang\\lua\\?.dll'
|
||
|
||
-- useful function for getting a property, or a default if not present.
|
||
function scite_GetProp(key,default)
|
||
local val = props[key]
|
||
if val and val ~= '' then return val
|
||
else return default end
|
||
end
|
||
|
||
function scite_GetPropBool(key,default)
|
||
local res = scite_GetProp(key,default)
|
||
if not res or res == '0' or res == 'false' then return false
|
||
else return true
|
||
end
|
||
end
|
||
|
||
local GTK = scite_GetProp('PLAT_GTK')
|
||
|
||
local _MarginClick,_DoubleClick,_SavePointLeft = {},{},{}
|
||
local _SavePointReached,_Open,_SwitchFile = {},{},{}
|
||
local _BeforeSave,_Save,_Char = {},{},{}
|
||
local _Word,_LineEd,_LineOut = {},{},{}
|
||
local _OpenSwitch = {}
|
||
local _UpdateUI = {}
|
||
local _UserListSelection
|
||
-- new with 1.74!
|
||
local _Key = {}
|
||
local _DwellStart = {}
|
||
local _Close = {}
|
||
-- new
|
||
local _remove = {}
|
||
local append = table.insert
|
||
local find = string.find
|
||
local size = table.getn
|
||
local sub = string.sub
|
||
local gsub = string.gsub
|
||
|
||
|
||
-- file must be quoted if it contains spaces!
|
||
function quote_if_needed(target)
|
||
local quote = '"'
|
||
if find(target,'%s') and sub(target,1,1) ~= quote then
|
||
target = quote..target..quote
|
||
end
|
||
return target
|
||
end
|
||
|
||
function OnUserListSelection(tp,str)
|
||
if _UserListSelection then
|
||
local callback = _UserListSelection
|
||
_UserListSelection = nil
|
||
return callback(str)
|
||
else return false end
|
||
end
|
||
|
||
local function DispatchOne(handlers,arg)
|
||
for i,handler in pairs(handlers) do
|
||
local fn = handler
|
||
if _remove[fn] then
|
||
handlers[i] = nil
|
||
_remove[fn] = nil
|
||
end
|
||
local ret = fn(arg)
|
||
if ret then return ret end
|
||
end
|
||
return false
|
||
end
|
||
|
||
local function Dispatch4(handlers,arg1,arg2,arg3,arg4)
|
||
for i,handler in pairs(handlers) do
|
||
local fn = handler
|
||
if _remove[fn] then
|
||
handlers[i] = nil
|
||
_remove[fn] = nil
|
||
end
|
||
local ret = fn(arg1,arg2,arg3,arg4)
|
||
if ret then return ret end
|
||
end
|
||
return false
|
||
end
|
||
|
||
DoDispatchOne = DispatchOne -- export this!
|
||
|
||
-- these are the standard SciTE Lua callbacks - we use them to call installed extman handlers!
|
||
function OnMarginClick()
|
||
return DispatchOne(_MarginClick)
|
||
end
|
||
|
||
function OnDoubleClick()
|
||
return DispatchOne(_DoubleClick)
|
||
end
|
||
|
||
function OnSavePointLeft()
|
||
return DispatchOne(_SavePointLeft)
|
||
end
|
||
|
||
function OnSavePointReached()
|
||
return DispatchOne(_SavePointReached)
|
||
end
|
||
|
||
function OnChar(ch)
|
||
return DispatchOne(_Char,ch)
|
||
end
|
||
|
||
function OnSave(file)
|
||
return DispatchOne(_Save,file)
|
||
end
|
||
|
||
function OnBeforeSave(file)
|
||
return DispatchOne(_BeforeSave,file)
|
||
end
|
||
|
||
function OnSwitchFile(file)
|
||
return DispatchOne(_SwitchFile,file)
|
||
end
|
||
|
||
function OnOpen(file)
|
||
return DispatchOne(_Open,file)
|
||
end
|
||
|
||
function OnUpdateUI()
|
||
if editor.Focus then
|
||
return DispatchOne(_UpdateUI)
|
||
else
|
||
return false
|
||
end
|
||
end
|
||
|
||
-- new with 1.74
|
||
function OnKey(key,shift,ctrl,alt)
|
||
return Dispatch4(_Key,key,shift,ctrl,alt)
|
||
end
|
||
|
||
function OnDwellStart(pos,s)
|
||
return Dispatch4(_DwellStart,pos,s)
|
||
end
|
||
|
||
function OnClose()
|
||
return DispatchOne(_Close)
|
||
end
|
||
|
||
-- may optionally ask that this handler be immediately
|
||
-- removed after it's called
|
||
local function append_unique(tbl,fn,rem)
|
||
local once_only
|
||
if type(fn) == 'string' then
|
||
once_only = fn == 'once'
|
||
fn = rem
|
||
rem = nil
|
||
if once_only then
|
||
_remove[fn] = fn
|
||
end
|
||
else
|
||
_remove[fn] = nil
|
||
end
|
||
local idx
|
||
for i,handler in pairs(tbl) do
|
||
if handler == fn then idx = i; break end
|
||
end
|
||
if idx then
|
||
if rem then
|
||
table.remove(tbl,idx)
|
||
end
|
||
else
|
||
if not rem then
|
||
append(tbl,fn)
|
||
end
|
||
end
|
||
end
|
||
ex_append_unique = append_unique
|
||
|
||
-- this is how you register your own handlers with extman
|
||
function scite_OnMarginClick(fn,rem)
|
||
append_unique(_MarginClick,fn,rem)
|
||
end
|
||
|
||
function scite_OnDoubleClick(fn,rem)
|
||
append_unique(_DoubleClick,fn,rem)
|
||
end
|
||
|
||
function scite_OnSavePointLeft(fn,rem)
|
||
append_unique(_SavePointLeft,fn,rem)
|
||
end
|
||
|
||
function scite_OnSavePointReached(fn,rem)
|
||
append_unique(_SavePointReached,fn,rem)
|
||
end
|
||
|
||
function scite_OnOpen(fn,rem)
|
||
append_unique(_Open,fn,rem)
|
||
end
|
||
|
||
function scite_OnSwitchFile(fn,rem)
|
||
append_unique(_SwitchFile,fn,rem)
|
||
end
|
||
|
||
function scite_OnBeforeSave(fn,rem)
|
||
append_unique(_BeforeSave,fn,rem)
|
||
end
|
||
|
||
function scite_OnSave(fn,rem)
|
||
append_unique(_Save,fn,rem)
|
||
end
|
||
|
||
function scite_OnUpdateUI(fn,rem)
|
||
append_unique(_UpdateUI,fn,rem)
|
||
end
|
||
|
||
function scite_OnChar(fn,rem)
|
||
append_unique(_Char,fn,rem)
|
||
end
|
||
|
||
function scite_OnOpenSwitch(fn,rem)
|
||
append_unique(_OpenSwitch,fn,rem)
|
||
end
|
||
|
||
--new 1.74
|
||
function scite_OnKey(fn,rem)
|
||
append_unique(_Key,fn,rem)
|
||
end
|
||
|
||
function scite_OnDwellStart(fn,rem)
|
||
append_unique(_DwellStart,fn,rem)
|
||
end
|
||
|
||
function scite_OnClose(fn,rem)
|
||
append_unique(_Close,fn,rem)
|
||
end
|
||
|
||
local function buffer_switch(f)
|
||
--- OnOpen() is also called if we move to a new folder
|
||
if not find(f,'[\\/]$') then
|
||
DispatchOne(_OpenSwitch,f)
|
||
end
|
||
end
|
||
|
||
scite_OnOpen(buffer_switch)
|
||
scite_OnSwitchFile(buffer_switch)
|
||
|
||
local next_user_id = 13 -- arbitrary
|
||
|
||
-- the handler is always reset!
|
||
function scite_UserListShow(list,start,fn)
|
||
local separators = {' ', ';', '@', '?', '~', ':'}
|
||
local separator
|
||
local s = table.concat(list)
|
||
for i, sep in ipairs(separators) do
|
||
if not string.find(s, sep, 1, true) then
|
||
s = table.concat(list, sep, start)
|
||
separator = sep
|
||
break
|
||
end
|
||
end
|
||
-- we could not find a good separator, set it arbitrarily
|
||
if not separator then
|
||
separator = '@'
|
||
s = table.concat(list, separator, start)
|
||
end
|
||
_UserListSelection = fn
|
||
local pane = editor
|
||
if not pane.Focus then pane = output end
|
||
pane.AutoCSeparator = string.byte(separator)
|
||
pane:UserListShow(next_user_id,s)
|
||
pane.AutoCSeparator = string.byte(' ')
|
||
return true
|
||
end
|
||
|
||
local word_start,in_word,current_word
|
||
-- (Nicolas) this is in Ascii as SciTE always passes chars in this "encoding" to OnChar
|
||
local wordchars = '[A-Za-z<>-<2D><>-<2D>]' -- wuz %w
|
||
|
||
local function on_word_char(s)
|
||
if not in_word then
|
||
if find(s,wordchars) then
|
||
-- we have hit a word!
|
||
word_start = editor.CurrentPos
|
||
in_word = true
|
||
current_word = s
|
||
end
|
||
else -- we're in a word
|
||
-- and it's another word character, so collect
|
||
if find(s,wordchars) then
|
||
current_word = current_word..s
|
||
else
|
||
-- leaving a word; call the handler
|
||
local word_end = editor.CurrentPos
|
||
DispatchOne(_Word, {word=current_word,
|
||
startp=word_start,endp=editor.CurrentPos,
|
||
ch = s
|
||
})
|
||
in_word = false
|
||
end
|
||
end
|
||
-- don't interfere with usual processing!
|
||
return false
|
||
end
|
||
|
||
function scite_OnWord(fn,rem)
|
||
append_unique(_Word,fn,rem)
|
||
if not rem then
|
||
scite_OnChar(on_word_char)
|
||
else
|
||
scite_OnChar(on_word_char,'remove')
|
||
end
|
||
end
|
||
|
||
local last_pos = 0
|
||
|
||
function get_line(pane,lineno)
|
||
if not pane then pane = editor end
|
||
if not lineno then
|
||
local line_pos = pane.CurrentPos
|
||
lineno = pane:LineFromPosition(line_pos)-1
|
||
end
|
||
-- strip linefeeds (Windows is a special case as usual!)
|
||
local endl = 2
|
||
if pane.EOLMode == 0 then endl = 3 end
|
||
local line = pane:GetLine(lineno)
|
||
if not line then return nil end
|
||
return string.sub(line,1,-endl)
|
||
end
|
||
|
||
-- export this useful function...
|
||
scite_Line = get_line
|
||
|
||
local function on_line_char(ch,was_output)
|
||
if ch == '\n' then
|
||
local in_editor = editor.Focus
|
||
if in_editor and not was_output then
|
||
DispatchOne(_LineEd,get_line(editor))
|
||
return false -- DO NOT interfere with any editor processing!
|
||
elseif not in_editor and was_output then
|
||
DispatchOne(_LineOut,get_line(output))
|
||
return true -- prevent SciTE from trying to evaluate the line
|
||
end
|
||
end
|
||
return false
|
||
end
|
||
|
||
local function on_line_editor_char(ch)
|
||
return on_line_char(ch,false)
|
||
end
|
||
|
||
local function on_line_output_char(ch)
|
||
return on_line_char(ch,true)
|
||
end
|
||
|
||
local function set_line_handler(fn,rem,handler,on_char)
|
||
append_unique(handler,fn,rem)
|
||
if not rem then
|
||
scite_OnChar(on_char)
|
||
else
|
||
scite_OnChar(on_char,'remove')
|
||
end
|
||
end
|
||
|
||
function scite_OnEditorLine(fn,rem)
|
||
set_line_handler(fn,rem,_LineEd,on_line_editor_char)
|
||
end
|
||
|
||
-- with this scheme, there is a primary handler, and secondary prompt handlers
|
||
-- can temporarily take charge of input. There is only one prompt in charge
|
||
-- at any particular time, however.
|
||
local primary_handler
|
||
|
||
function scite_OnOutputLine(fn,rem)
|
||
if not rem then
|
||
if not primary_handler then primary_handler = fn end
|
||
end
|
||
_LineOut = {}
|
||
set_line_handler(fn,rem,_LineOut,on_line_output_char)
|
||
if rem and fn ~= primary_handler then
|
||
set_line_handler(primary_handler,false,_LineOut,on_line_output_char)
|
||
end
|
||
end
|
||
|
||
local path_pattern
|
||
local tempfile
|
||
local dirsep
|
||
|
||
if GTK then
|
||
tempfile = '/tmp/.scite-temp-files'
|
||
path_pattern = '(.*)/[^%./]+%.%w+$'
|
||
dirsep = '/'
|
||
else
|
||
tempfile = '\\scite_temp1'
|
||
path_pattern = '(.*)\\[^%.\\]+%.%w+$'
|
||
dirsep = '\\'
|
||
end
|
||
|
||
function path_of(s)
|
||
local _,_,res = find(s,path_pattern)
|
||
if _ then return res else return s end
|
||
end
|
||
|
||
local extman_path = path_of(props['ext.lua.startup.script'])
|
||
local lua_path = scite_GetProp('ext.lua.directory',extman_path..dirsep..'scite_lua')
|
||
|
||
function extman_Path()
|
||
return extman_path
|
||
end
|
||
|
||
-- this version of scite-gdb uses the new spawner extension library.
|
||
local fn,err,spawner_path
|
||
if package then loadlib = package.loadlib end
|
||
-- by default, the spawner lib sits next to extman.lua
|
||
spawner_path = scite_GetProp('spawner.extension.path',extman_path)
|
||
if GTK then
|
||
fn,err = loadlib(spawner_path..'/unix-spawner-ex.so','luaopen_spawner')
|
||
else
|
||
fn,err = loadlib(spawner_path..'\\spawner-ex.dll','luaopen_spawner')
|
||
end
|
||
if fn then
|
||
fn() -- register spawner
|
||
else
|
||
print('cannot load spawner '..err)
|
||
end
|
||
|
||
-- a general popen function that uses the spawner library if found; otherwise falls back
|
||
-- on os.execute
|
||
function scite_Popen(cmd)
|
||
if spawner then
|
||
return spawner.popen(cmd)
|
||
else
|
||
cmd = cmd..' > '..tempfile
|
||
if GTK then -- io.popen is dodgy; don't use it!
|
||
os.execute(cmd)
|
||
else
|
||
if Execute then -- scite_other was found!
|
||
Execute(cmd)
|
||
else
|
||
os.execute(cmd)
|
||
end
|
||
end
|
||
return io.open(tempfile)
|
||
end
|
||
end
|
||
|
||
function dirmask(mask,isdir)
|
||
local attrib = ''
|
||
if isdir then
|
||
if not GTK then
|
||
attrib = ' /A:D '
|
||
else
|
||
attrib = ' -F '
|
||
end
|
||
end
|
||
if not GTK then
|
||
mask = gsub(mask,'/','\\')
|
||
return 'dir /b '..attrib..quote_if_needed(mask)
|
||
else
|
||
return 'ls -1 '..attrib..quote_if_needed(mask)
|
||
end
|
||
end
|
||
|
||
-- p = globtopattern(g)
|
||
--
|
||
-- Converts glob string (g) into Lua pattern string (p).
|
||
-- Always succeeds.
|
||
--
|
||
-- Warning: could be better tested.
|
||
--
|
||
-- (c) 2008 D.Manura, Licensed under the same terms as Lua (MIT License).
|
||
local function globtopattern(g)
|
||
-- Some useful references:
|
||
-- - apr_fnmatch in Apache APR. For example,
|
||
-- http://apr.apache.org/docs/apr/1.3/group__apr__fnmatch.html
|
||
-- which cites POSIX 1003.2-1992, section B.6.
|
||
|
||
local p = "^" -- pattern being built
|
||
local i = 0 -- index in g
|
||
local c -- char at index i in g.
|
||
|
||
-- unescape glob char
|
||
local function unescape()
|
||
if c == '\\' then
|
||
i = i + 1; c = g:sub(i,i)
|
||
if c == '' then
|
||
p = '[^]'
|
||
return false
|
||
end
|
||
end
|
||
return true
|
||
end
|
||
|
||
-- escape pattern char
|
||
local function escape(c)
|
||
return c:match("^%w$") and c or '%' .. c
|
||
end
|
||
|
||
-- Convert tokens at end of charset.
|
||
local function charset_end()
|
||
while 1 do
|
||
if c == '' then
|
||
p = '[^]'
|
||
break
|
||
elseif c == ']' then
|
||
p = p .. ']'
|
||
break
|
||
else
|
||
if not unescape() then break end
|
||
local c1 = c
|
||
i = i + 1; c = g:sub(i,i)
|
||
if c == '' then
|
||
p = '[^]'
|
||
break
|
||
elseif c == '-' then
|
||
i = i + 1; c = g:sub(i,i)
|
||
if c == '' then
|
||
p = '[^]'
|
||
break
|
||
elseif c == ']' then
|
||
p = p .. escape(c1) .. '%-]'
|
||
break
|
||
else
|
||
if not unescape() then break end
|
||
p = p .. escape(c1) .. '-' .. escape(c)
|
||
end
|
||
elseif c == ']' then
|
||
p = p .. escape(c1) .. ']'
|
||
break
|
||
else
|
||
p = p .. escape(c1)
|
||
i = i - 1 -- put back
|
||
end
|
||
end
|
||
i = i + 1; c = g:sub(i,i)
|
||
end
|
||
end
|
||
|
||
-- Convert tokens in charset.
|
||
local function charset()
|
||
p = p .. '['
|
||
i = i + 1; c = g:sub(i,i)
|
||
if c == '' or c == ']' then
|
||
p = p .. '[^]'
|
||
elseif c == '^' or c == '!' then
|
||
p = p .. '^'
|
||
i = i + 1; c = g:sub(i,i)
|
||
if c == ']' then
|
||
-- ignored
|
||
else
|
||
charset_end()
|
||
end
|
||
else
|
||
charset_end()
|
||
end
|
||
end
|
||
|
||
-- Convert tokens.
|
||
while 1 do
|
||
i = i + 1; c = g:sub(i,i)
|
||
if c == '' then
|
||
p = p .. '$'
|
||
break
|
||
elseif c == '?' then
|
||
p = p .. '.'
|
||
elseif c == '*' then
|
||
p = p .. '.*'
|
||
elseif c == '[' then
|
||
charset()
|
||
elseif c == '\\' then
|
||
i = i + 1; c = g:sub(i,i)
|
||
if c == '' then
|
||
p = p .. '\\$'
|
||
break
|
||
end
|
||
p = p .. escape(c)
|
||
else
|
||
p = p .. escape(c)
|
||
end
|
||
end
|
||
return p
|
||
end
|
||
|
||
-- grab all files matching @mask, which is assumed to be a path with a wildcard.
|
||
-- 2008-06-27 Now uses David Manura's globtopattern(), which is not fooled by cases
|
||
-- like test.lua and test.lua~ !
|
||
function scite_Files(mask)
|
||
local f,path,pat,cmd,_
|
||
if not GTK then
|
||
cmd = dirmask(mask)
|
||
path = mask:match('(.*\\)') or '.\\'
|
||
local file = mask:match('([^\\]*)$')
|
||
pat = globtopattern(file)
|
||
else
|
||
cmd = 'ls -1 '..mask
|
||
path = ''
|
||
end
|
||
f = scite_Popen(cmd)
|
||
local files = {}
|
||
if not f then return files end
|
||
|
||
for line in f:lines() do
|
||
if not pat or line:match(pat) then
|
||
append(files,path..line)
|
||
end
|
||
end
|
||
f:close()
|
||
return files
|
||
end
|
||
|
||
-- grab all directories in @path, excluding anything that matches @exclude_path
|
||
-- As a special exception, will also any directory called 'examples' ;)
|
||
function scite_Directories(path,exclude_pat)
|
||
local cmd
|
||
--print(path)
|
||
if not GTK then
|
||
cmd = dirmask(path..'\\*.',true)
|
||
else
|
||
cmd = dirmask(path,true)
|
||
end
|
||
path = path..dirsep
|
||
local f = scite_Popen(cmd)
|
||
local files = {}
|
||
if not f then return files end
|
||
for line in f:lines() do
|
||
-- print(line)
|
||
if GTK then
|
||
if line:sub(-1,-1) == dirsep then
|
||
line = line:sub(1,-2)
|
||
else
|
||
line = nil
|
||
end
|
||
end
|
||
if line and not line:find(exclude_pat) and line ~= 'examples' then
|
||
append(files,path..line)
|
||
end
|
||
end
|
||
f:close()
|
||
return files
|
||
end
|
||
|
||
function scite_FileExists(f)
|
||
local f = io.open(f)
|
||
if not f then return false
|
||
else
|
||
f:close()
|
||
return true
|
||
end
|
||
end
|
||
|
||
function scite_CurrentFile()
|
||
return props['FilePath']
|
||
end
|
||
|
||
-- (Nicolas)
|
||
if GTK then
|
||
function scite_DirectoryExists(path)
|
||
return os.execute('test -d "'..path..'"') == 0
|
||
end
|
||
else
|
||
-- what is the Win32 equivalent??
|
||
function scite_DirectoryExists(path)
|
||
return true
|
||
end
|
||
end
|
||
|
||
function split(s,delim)
|
||
res = {}
|
||
while true do
|
||
p = find(s,delim)
|
||
if not p then
|
||
append(res,s)
|
||
return res
|
||
end
|
||
append(res,sub(s,1,p-1))
|
||
s = sub(s,p+1)
|
||
end
|
||
end
|
||
|
||
function splitv(s,delim)
|
||
return unpack(split(s,delim))
|
||
end
|
||
|
||
local idx = 10
|
||
local shortcuts_used = {}
|
||
local alt_letter_map = {}
|
||
local alt_letter_map_init = false
|
||
local name_id_map = {}
|
||
|
||
local function set_command(name,cmd,mode)
|
||
local _,_,pattern,md = find(mode,'(.+){(.+)}')
|
||
if not _ then
|
||
pattern = mode
|
||
md = 'savebefore:no'
|
||
end
|
||
local which = '.'..idx..pattern
|
||
props['command.name'..which] = name
|
||
props['command'..which] = cmd
|
||
props['command.subsystem'..which] = '3'
|
||
props['command.mode'..which] = md
|
||
name_id_map[name] = 1100+idx
|
||
return which
|
||
end
|
||
|
||
local function check_gtk_alt_shortcut(shortcut,name)
|
||
-- Alt+<letter> shortcuts don't work for GTK, so handle them directly...
|
||
local _,_,letter = shortcut:find('Alt%+([A-Z])$')
|
||
if _ then
|
||
alt_letter_map[letter:lower()] = name
|
||
if not alt_letter_map_init then
|
||
alt_letter_map_init = true
|
||
scite_OnKey(function(key,shift,ctrl,alt)
|
||
if alt and key < 255 then
|
||
local ch = string.char(key)
|
||
if alt_letter_map[ch] then
|
||
scite_MenuCommand(alt_letter_map[ch])
|
||
end
|
||
end
|
||
end)
|
||
end
|
||
end
|
||
end
|
||
|
||
local function set_shortcut(shortcut,name,which)
|
||
if shortcut == 'Context' then
|
||
local usr = 'user.context.menu'
|
||
if props[usr] == '' then -- force a separator
|
||
props[usr] = '|'
|
||
end
|
||
props[usr] = props[usr]..'|'..name..'|'..(1100+idx)..'|'
|
||
else
|
||
local cmd = shortcuts_used[shortcut]
|
||
if cmd then
|
||
print('Error: shortcut already used in "'..cmd..'"')
|
||
else
|
||
shortcuts_used[shortcut] = name
|
||
if GTK then check_gtk_alt_shortcut(shortcut,name) end
|
||
props['command.shortcut'..which] = shortcut
|
||
end
|
||
end
|
||
end
|
||
|
||
-- allows you to bind given Lua functions to shortcut keys
|
||
-- without messing around in the properties files!
|
||
-- Either a string or a table of strings; the string format is either
|
||
-- menu text|Lua command|shortcut
|
||
-- or
|
||
-- menu text|Lua command|mode|shortcut
|
||
-- where 'mode' is the file extension which this command applies to,
|
||
-- e.g. 'lua' or 'c', optionally followed by {mode specifier}, where 'mode specifier'
|
||
-- is the same as documented under 'command.mode'
|
||
-- 'shortcut' can be a usual SciTE key specifier, like 'Alt+R' or 'Ctrl+Shift+F1',
|
||
-- _or_ it can be 'Context', meaning that the menu item should also be added
|
||
-- to the right-hand click context menu.
|
||
function scite_Command(tbl)
|
||
if type(tbl) == 'string' then
|
||
tbl = {tbl}
|
||
end
|
||
for i,v in pairs(tbl) do
|
||
local name,cmd,mode,shortcut = splitv(v,'|')
|
||
if not shortcut then
|
||
shortcut = mode
|
||
mode = '.*'
|
||
else
|
||
mode = '.'..mode
|
||
end
|
||
-- has this command been defined before?
|
||
local old_idx = 0
|
||
for ii = 10,idx do
|
||
if props['command.name.'..ii..mode] == name then old_idx = ii end
|
||
end
|
||
if old_idx == 0 then
|
||
local which = set_command(name,cmd,mode)
|
||
if shortcut then
|
||
set_shortcut(shortcut,name,which)
|
||
end
|
||
idx = idx + 1
|
||
end
|
||
end
|
||
end
|
||
|
||
-- use this to launch Lua Tool menu commands directly by name
|
||
-- (commands are not guaranteed to work properly if you just call the Lua function)
|
||
function scite_MenuCommand(cmd)
|
||
if type(cmd) == 'string' then
|
||
cmd = name_id_map[cmd]
|
||
if not cmd then return end
|
||
end
|
||
scite.MenuCommand(cmd)
|
||
end
|
||
|
||
local loaded = {}
|
||
local current_filepath
|
||
|
||
-- this will quietly fail....
|
||
local function silent_dofile(f)
|
||
if scite_FileExists(f) then
|
||
if not loaded[f] then
|
||
dofile(f)
|
||
loaded[f] = true
|
||
end
|
||
return true
|
||
end
|
||
return false
|
||
end
|
||
|
||
function scite_dofile(f)
|
||
f = extman_path..'/'..f
|
||
silent_dofile(f)
|
||
end
|
||
|
||
function scite_require(f)
|
||
local path = lua_path..dirsep..f
|
||
if not silent_dofile(path) then
|
||
silent_dofile(current_filepath..dirsep..f)
|
||
end
|
||
end
|
||
|
||
if not GTK then
|
||
scite_dofile 'scite_other.lua'
|
||
end
|
||
|
||
if not scite_DirectoryExists(lua_path) then
|
||
print('Error: directory '..lua_path..' not found')
|
||
return
|
||
end
|
||
|
||
function load_script_list(script_list,path)
|
||
if not script_list then
|
||
print('Error: no files found in '..path)
|
||
else
|
||
current_filepath = path
|
||
for i,file in pairs(script_list) do
|
||
silent_dofile(file)
|
||
end
|
||
end
|
||
end
|
||
|
||
-- Load all scripts in the lua_path (usually 'scite_lua'), including within any subdirectories
|
||
-- that aren't 'examples' or begin with a '_'
|
||
local script_list = scite_Files(lua_path..dirsep..'*.lua')
|
||
load_script_list(script_list,lua_path)
|
||
local dirs = scite_Directories(lua_path,'^_')
|
||
for i,dir in ipairs(dirs) do
|
||
load_script_list(scite_Files(dir..dirsep..'*.lua'),dir)
|
||
end
|
||
|
||
function scite_WordAtPos(pos)
|
||
if not pos then pos = editor.CurrentPos end
|
||
local p2 = editor:WordEndPosition(pos,true)
|
||
local p1 = editor:WordStartPosition(pos,true)
|
||
if p2 > p1 then
|
||
return editor:textrange(p1,p2)
|
||
end
|
||
end
|
||
|
||
function scite_GetSelOrWord()
|
||
local s = editor:GetSelText()
|
||
if s == '' then
|
||
return scite_WordAtPos()
|
||
else
|
||
return s
|
||
end
|
||
end
|
||
|
||
--~ scite_Command 'Reload Script|reload_script|Shift+Ctrl+R'
|
||
|
||
--~ function reload_script()
|
||
--~ current_file = scite_CurrentFile()
|
||
--~ print('Reloading... '..current_file)
|
||
--~ loaded[current_file] = false
|
||
--~ silent_dofile(current_file)
|
||
--~ end
|
||
|
||
--~ require"remdebug.engine"
|
||
--~ remdebug.engine.start()
|
||
|