/extman/extman.lua

http://github.com/davidm/lua-inspect · Lua · 896 lines · 694 code · 105 blank · 97 comment · 178 complexity · 2893d58b2886ad899cbb40ef16a67ab6 MD5 · raw file

  1. -- Extman is a Lua script manager for SciTE. It enables multiple scripts to capture standard events
  2. -- without interfering with each other. For instance, scite_OnDoubleClick() will register handlers
  3. -- for scripts that need to know when a double-click event has happened. (To know whether it
  4. -- was in the output or editor pane, just test editor.Focus). It provides a useful function scite_Command
  5. -- which allows you to define new commands without messing around with property files (see the
  6. -- examples in the scite_lua directory.)
  7. -- extman defines three new convenience handlers as well:
  8. --scite_OnWord (called when user has entered a word)
  9. --scite_OnEditorLine (called when a line is entered into the editor)
  10. --scite_OnOutputLine (called when a line is entered into the output pane)
  11. -- this is an opportunity for you to make regular Lua packages available to SciTE
  12. --~ package.path = package.path..';C:\\lang\\lua\\lua\\?.lua'
  13. --~ package.cpath = package.cpath..';c:\\lang\\lua\\?.dll'
  14. package.cpath = package.cpath..';c:\\lua\\clibs\\?.dll'
  15. -- useful function for getting a property, or a default if not present.
  16. function scite_GetProp(key,default)
  17. local val = props[key]
  18. if val and val ~= '' then return val
  19. else return default end
  20. end
  21. function scite_GetPropBool(key,default)
  22. local res = scite_GetProp(key,default)
  23. if not res or res == '0' or res == 'false' then return false
  24. else return true
  25. end
  26. end
  27. local GTK = scite_GetProp('PLAT_GTK')
  28. local _MarginClick,_DoubleClick,_SavePointLeft = {},{},{}
  29. local _SavePointReached,_Open,_SwitchFile = {},{},{}
  30. local _BeforeSave,_Save,_Char = {},{},{}
  31. local _Word,_LineEd,_LineOut = {},{},{}
  32. local _OpenSwitch = {}
  33. local _UpdateUI = {}
  34. local _UserListSelection
  35. -- new with 1.74!
  36. local _Key = {}
  37. local _DwellStart = {}
  38. local _Close = {}
  39. -- new
  40. local _remove = {}
  41. local append = table.insert
  42. local find = string.find
  43. local size = table.getn
  44. local sub = string.sub
  45. local gsub = string.gsub
  46. -- file must be quoted if it contains spaces!
  47. function quote_if_needed(target)
  48. local quote = '"'
  49. if find(target,'%s') and sub(target,1,1) ~= quote then
  50. target = quote..target..quote
  51. end
  52. return target
  53. end
  54. function OnUserListSelection(tp,str)
  55. if _UserListSelection then
  56. local callback = _UserListSelection
  57. _UserListSelection = nil
  58. return callback(str)
  59. else return false end
  60. end
  61. local function DispatchOne(handlers,arg)
  62. for i,handler in pairs(handlers) do
  63. local fn = handler
  64. if _remove[fn] then
  65. handlers[i] = nil
  66. _remove[fn] = nil
  67. end
  68. local ret = fn(arg)
  69. if ret then return ret end
  70. end
  71. return false
  72. end
  73. local function Dispatch4(handlers,arg1,arg2,arg3,arg4)
  74. for i,handler in pairs(handlers) do
  75. local fn = handler
  76. if _remove[fn] then
  77. handlers[i] = nil
  78. _remove[fn] = nil
  79. end
  80. local ret = fn(arg1,arg2,arg3,arg4)
  81. if ret then return ret end
  82. end
  83. return false
  84. end
  85. DoDispatchOne = DispatchOne -- export this!
  86. -- these are the standard SciTE Lua callbacks - we use them to call installed extman handlers!
  87. function OnMarginClick()
  88. return DispatchOne(_MarginClick)
  89. end
  90. function OnDoubleClick()
  91. return DispatchOne(_DoubleClick)
  92. end
  93. function OnSavePointLeft()
  94. return DispatchOne(_SavePointLeft)
  95. end
  96. function OnSavePointReached()
  97. return DispatchOne(_SavePointReached)
  98. end
  99. function OnChar(ch)
  100. return DispatchOne(_Char,ch)
  101. end
  102. function OnSave(file)
  103. return DispatchOne(_Save,file)
  104. end
  105. function OnBeforeSave(file)
  106. return DispatchOne(_BeforeSave,file)
  107. end
  108. function OnSwitchFile(file)
  109. return DispatchOne(_SwitchFile,file)
  110. end
  111. function OnOpen(file)
  112. return DispatchOne(_Open,file)
  113. end
  114. function OnUpdateUI()
  115. if editor.Focus then
  116. return DispatchOne(_UpdateUI)
  117. else
  118. return false
  119. end
  120. end
  121. -- new with 1.74
  122. function OnKey(key,shift,ctrl,alt)
  123. return Dispatch4(_Key,key,shift,ctrl,alt)
  124. end
  125. function OnDwellStart(pos,s)
  126. return Dispatch4(_DwellStart,pos,s)
  127. end
  128. function OnClose()
  129. return DispatchOne(_Close)
  130. end
  131. -- may optionally ask that this handler be immediately
  132. -- removed after it's called
  133. local function append_unique(tbl,fn,rem)
  134. local once_only
  135. if type(fn) == 'string' then
  136. once_only = fn == 'once'
  137. fn = rem
  138. rem = nil
  139. if once_only then
  140. _remove[fn] = fn
  141. end
  142. else
  143. _remove[fn] = nil
  144. end
  145. local idx
  146. for i,handler in pairs(tbl) do
  147. if handler == fn then idx = i; break end
  148. end
  149. if idx then
  150. if rem then
  151. table.remove(tbl,idx)
  152. end
  153. else
  154. if not rem then
  155. append(tbl,fn)
  156. end
  157. end
  158. end
  159. ex_append_unique = append_unique
  160. -- this is how you register your own handlers with extman
  161. function scite_OnMarginClick(fn,rem)
  162. append_unique(_MarginClick,fn,rem)
  163. end
  164. function scite_OnDoubleClick(fn,rem)
  165. append_unique(_DoubleClick,fn,rem)
  166. end
  167. function scite_OnSavePointLeft(fn,rem)
  168. append_unique(_SavePointLeft,fn,rem)
  169. end
  170. function scite_OnSavePointReached(fn,rem)
  171. append_unique(_SavePointReached,fn,rem)
  172. end
  173. function scite_OnOpen(fn,rem)
  174. append_unique(_Open,fn,rem)
  175. end
  176. function scite_OnSwitchFile(fn,rem)
  177. append_unique(_SwitchFile,fn,rem)
  178. end
  179. function scite_OnBeforeSave(fn,rem)
  180. append_unique(_BeforeSave,fn,rem)
  181. end
  182. function scite_OnSave(fn,rem)
  183. append_unique(_Save,fn,rem)
  184. end
  185. function scite_OnUpdateUI(fn,rem)
  186. append_unique(_UpdateUI,fn,rem)
  187. end
  188. function scite_OnChar(fn,rem)
  189. append_unique(_Char,fn,rem)
  190. end
  191. function scite_OnOpenSwitch(fn,rem)
  192. append_unique(_OpenSwitch,fn,rem)
  193. end
  194. --new 1.74
  195. function scite_OnKey(fn,rem)
  196. append_unique(_Key,fn,rem)
  197. end
  198. function scite_OnDwellStart(fn,rem)
  199. append_unique(_DwellStart,fn,rem)
  200. end
  201. function scite_OnClose(fn,rem)
  202. append_unique(_Close,fn,rem)
  203. end
  204. local function buffer_switch(f)
  205. --- OnOpen() is also called if we move to a new folder
  206. if not find(f,'[\\/]$') then
  207. DispatchOne(_OpenSwitch,f)
  208. end
  209. end
  210. scite_OnOpen(buffer_switch)
  211. scite_OnSwitchFile(buffer_switch)
  212. local next_user_id = 13 -- arbitrary
  213. -- the handler is always reset!
  214. function scite_UserListShow(list,start,fn)
  215. local separators = {' ', ';', '@', '?', '~', ':'}
  216. local separator
  217. local s = table.concat(list)
  218. for i, sep in ipairs(separators) do
  219. if not string.find(s, sep, 1, true) then
  220. s = table.concat(list, sep, start)
  221. separator = sep
  222. break
  223. end
  224. end
  225. -- we could not find a good separator, set it arbitrarily
  226. if not separator then
  227. separator = '@'
  228. s = table.concat(list, separator, start)
  229. end
  230. _UserListSelection = fn
  231. local pane = editor
  232. if not pane.Focus then pane = output end
  233. pane.AutoCSeparator = string.byte(separator)
  234. pane:UserListShow(next_user_id,s)
  235. pane.AutoCSeparator = string.byte(' ')
  236. return true
  237. end
  238. local word_start,in_word,current_word
  239. -- (Nicolas) this is in Ascii as SciTE always passes chars in this "encoding" to OnChar
  240. local wordchars = '[A-Za-zÀ-Ýà-ÿ]' -- wuz %w
  241. local function on_word_char(s)
  242. if not in_word then
  243. if find(s,wordchars) then
  244. -- we have hit a word!
  245. word_start = editor.CurrentPos
  246. in_word = true
  247. current_word = s
  248. end
  249. else -- we're in a word
  250. -- and it's another word character, so collect
  251. if find(s,wordchars) then
  252. current_word = current_word..s
  253. else
  254. -- leaving a word; call the handler
  255. local word_end = editor.CurrentPos
  256. DispatchOne(_Word, {word=current_word,
  257. startp=word_start,endp=editor.CurrentPos,
  258. ch = s
  259. })
  260. in_word = false
  261. end
  262. end
  263. -- don't interfere with usual processing!
  264. return false
  265. end
  266. function scite_OnWord(fn,rem)
  267. append_unique(_Word,fn,rem)
  268. if not rem then
  269. scite_OnChar(on_word_char)
  270. else
  271. scite_OnChar(on_word_char,'remove')
  272. end
  273. end
  274. local last_pos = 0
  275. function get_line(pane,lineno)
  276. if not pane then pane = editor end
  277. if not lineno then
  278. local line_pos = pane.CurrentPos
  279. lineno = pane:LineFromPosition(line_pos)-1
  280. end
  281. -- strip linefeeds (Windows is a special case as usual!)
  282. local endl = 2
  283. if pane.EOLMode == 0 then endl = 3 end
  284. local line = pane:GetLine(lineno)
  285. if not line then return nil end
  286. return string.sub(line,1,-endl)
  287. end
  288. -- export this useful function...
  289. scite_Line = get_line
  290. local function on_line_char(ch,was_output)
  291. if ch == '\n' then
  292. local in_editor = editor.Focus
  293. if in_editor and not was_output then
  294. DispatchOne(_LineEd,get_line(editor))
  295. return false -- DO NOT interfere with any editor processing!
  296. elseif not in_editor and was_output then
  297. DispatchOne(_LineOut,get_line(output))
  298. return true -- prevent SciTE from trying to evaluate the line
  299. end
  300. end
  301. return false
  302. end
  303. local function on_line_editor_char(ch)
  304. return on_line_char(ch,false)
  305. end
  306. local function on_line_output_char(ch)
  307. return on_line_char(ch,true)
  308. end
  309. local function set_line_handler(fn,rem,handler,on_char)
  310. append_unique(handler,fn,rem)
  311. if not rem then
  312. scite_OnChar(on_char)
  313. else
  314. scite_OnChar(on_char,'remove')
  315. end
  316. end
  317. function scite_OnEditorLine(fn,rem)
  318. set_line_handler(fn,rem,_LineEd,on_line_editor_char)
  319. end
  320. -- with this scheme, there is a primary handler, and secondary prompt handlers
  321. -- can temporarily take charge of input. There is only one prompt in charge
  322. -- at any particular time, however.
  323. local primary_handler
  324. function scite_OnOutputLine(fn,rem)
  325. if not rem then
  326. if not primary_handler then primary_handler = fn end
  327. end
  328. _LineOut = {}
  329. set_line_handler(fn,rem,_LineOut,on_line_output_char)
  330. if rem and fn ~= primary_handler then
  331. set_line_handler(primary_handler,false,_LineOut,on_line_output_char)
  332. end
  333. end
  334. local path_pattern
  335. local tempfile
  336. local dirsep
  337. if GTK then
  338. tempfile = '/tmp/.scite-temp-files'
  339. path_pattern = '(.*)/[^%./]+%.%w+$'
  340. dirsep = '/'
  341. else
  342. tempfile = os.getenv 'TMP' .. '\\scite_temp1'
  343. path_pattern = '(.*)[\\/][^%.\\/]+%.%w+$'
  344. dirsep = '\\'
  345. end
  346. function path_of(s)
  347. local _,_,res = find(s,path_pattern)
  348. if _ then return res else return s end
  349. end
  350. local extman_path = path_of(props['ext.lua.startup.script'])
  351. local lua_path = scite_GetProp('ext.lua.directory',extman_path..dirsep..'scite_lua')
  352. props['ext.lua.directory'] = lua_path:gsub('[\\/]$', '')
  353. fn,err = package.loadlib(extman_path.."/gui.dll","luaopen_gui")
  354. if fn then fn() else
  355. --DISABLED:print(err)
  356. end
  357. function extman_Path()
  358. return extman_path
  359. end
  360. -- this version of scite-gdb uses the new spawner extension library.
  361. local fn,err,spawner_path
  362. if package then loadlib = package.loadlib end
  363. -- by default, the spawner lib sits next to extman.lua
  364. spawner_path = scite_GetProp('spawner.extension.path',extman_path)
  365. if GTK then
  366. fn,err = loadlib(spawner_path..'/unix-spawner-ex.so','luaopen_spawner')
  367. else
  368. fn,err = loadlib(spawner_path..'\\spawner-ex.dll','luaopen_spawner')
  369. end
  370. if fn then
  371. fn() -- register spawner
  372. else
  373. --DISABLED: print('cannot load spawner '..err)
  374. end
  375. -- a general popen function that uses the spawner library if found; otherwise falls back
  376. -- on os.execute
  377. function scite_Popen(cmd)
  378. if spawner then
  379. return spawner.popen(cmd)
  380. else
  381. cmd = cmd..' > '..tempfile
  382. if GTK then -- io.popen is dodgy; don't use it!
  383. os.execute(cmd)
  384. else
  385. if Execute then -- scite_other was found!
  386. Execute(cmd)
  387. else
  388. os.execute(cmd)
  389. end
  390. end
  391. return io.open(tempfile)
  392. end
  393. end
  394. function dirmask(mask,isdir)
  395. local attrib = ''
  396. if isdir then
  397. if not GTK then
  398. attrib = ' /A:D '
  399. else
  400. attrib = ' -F '
  401. end
  402. end
  403. if not GTK then
  404. mask = gsub(mask,'/','\\')
  405. return 'dir /b '..attrib..quote_if_needed(mask)
  406. else
  407. return 'ls -1 '..attrib..quote_if_needed(mask)
  408. end
  409. end
  410. -- p = globtopattern(g)
  411. --
  412. -- Converts glob string (g) into Lua pattern string (p).
  413. -- Always succeeds.
  414. --
  415. -- Warning: could be better tested.
  416. --
  417. -- (c) 2008 D.Manura, Licensed under the same terms as Lua (MIT License).
  418. local function globtopattern(g)
  419. -- Some useful references:
  420. -- - apr_fnmatch in Apache APR. For example,
  421. -- http://apr.apache.org/docs/apr/1.3/group__apr__fnmatch.html
  422. -- which cites POSIX 1003.2-1992, section B.6.
  423. local p = "^" -- pattern being built
  424. local i = 0 -- index in g
  425. local c -- char at index i in g.
  426. -- unescape glob char
  427. local function unescape()
  428. if c == '\\' then
  429. i = i + 1; c = g:sub(i,i)
  430. if c == '' then
  431. p = '[^]'
  432. return false
  433. end
  434. end
  435. return true
  436. end
  437. -- escape pattern char
  438. local function escape(c)
  439. return c:match("^%w$") and c or '%' .. c
  440. end
  441. -- Convert tokens at end of charset.
  442. local function charset_end()
  443. while 1 do
  444. if c == '' then
  445. p = '[^]'
  446. break
  447. elseif c == ']' then
  448. p = p .. ']'
  449. break
  450. else
  451. if not unescape() then break end
  452. local c1 = c
  453. i = i + 1; c = g:sub(i,i)
  454. if c == '' then
  455. p = '[^]'
  456. break
  457. elseif c == '-' then
  458. i = i + 1; c = g:sub(i,i)
  459. if c == '' then
  460. p = '[^]'
  461. break
  462. elseif c == ']' then
  463. p = p .. escape(c1) .. '%-]'
  464. break
  465. else
  466. if not unescape() then break end
  467. p = p .. escape(c1) .. '-' .. escape(c)
  468. end
  469. elseif c == ']' then
  470. p = p .. escape(c1) .. ']'
  471. break
  472. else
  473. p = p .. escape(c1)
  474. i = i - 1 -- put back
  475. end
  476. end
  477. i = i + 1; c = g:sub(i,i)
  478. end
  479. end
  480. -- Convert tokens in charset.
  481. local function charset()
  482. p = p .. '['
  483. i = i + 1; c = g:sub(i,i)
  484. if c == '' or c == ']' then
  485. p = p .. '[^]'
  486. elseif c == '^' or c == '!' then
  487. p = p .. '^'
  488. i = i + 1; c = g:sub(i,i)
  489. if c == ']' then
  490. -- ignored
  491. else
  492. charset_end()
  493. end
  494. else
  495. charset_end()
  496. end
  497. end
  498. -- Convert tokens.
  499. while 1 do
  500. i = i + 1; c = g:sub(i,i)
  501. if c == '' then
  502. p = p .. '$'
  503. break
  504. elseif c == '?' then
  505. p = p .. '.'
  506. elseif c == '*' then
  507. p = p .. '.*'
  508. elseif c == '[' then
  509. charset()
  510. elseif c == '\\' then
  511. i = i + 1; c = g:sub(i,i)
  512. if c == '' then
  513. p = p .. '\\$'
  514. break
  515. end
  516. p = p .. escape(c)
  517. else
  518. p = p .. escape(c)
  519. end
  520. end
  521. return p
  522. end
  523. -- grab all files matching @mask, which is assumed to be a path with a wildcard.
  524. -- 2008-06-27 Now uses David Manura's globtopattern(), which is not fooled by cases
  525. -- like test.lua and test.lua~ !
  526. function scite_Files(mask)
  527. local f,path,pat,cmd,_
  528. if not GTK then
  529. cmd = dirmask(mask)
  530. path = mask:match('(.*\\)') or '.\\'
  531. local file = mask:match('([^\\]*)$')
  532. pat = globtopattern(file)
  533. else
  534. cmd = 'ls -1 '..mask
  535. path = ''
  536. end
  537. f = scite_Popen(cmd)
  538. local files = {}
  539. if not f then return files end
  540. for line in f:lines() do
  541. if not pat or line:match(pat) then
  542. append(files,path..line)
  543. end
  544. end
  545. f:close()
  546. return files
  547. end
  548. -- grab all directories in @path, excluding anything that matches @exclude_path
  549. -- As a special exception, will also any directory called 'examples' ;)
  550. function scite_Directories(path,exclude_pat)
  551. local cmd
  552. --print(path)
  553. if not GTK then
  554. cmd = dirmask(path..'\\*.',true)
  555. else
  556. cmd = dirmask(path,true)
  557. end
  558. path = path..dirsep
  559. local f = scite_Popen(cmd)
  560. local files = {}
  561. if not f then return files end
  562. for line in f:lines() do
  563. -- print(line)
  564. if GTK then
  565. if line:sub(-1,-1) == dirsep then
  566. line = line:sub(1,-2)
  567. else
  568. line = nil
  569. end
  570. end
  571. if line and not line:find(exclude_pat) and line ~= 'examples' then
  572. append(files,path..line)
  573. end
  574. end
  575. f:close()
  576. return files
  577. end
  578. function scite_FileExists(f)
  579. local f = io.open(f)
  580. if not f then return false
  581. else
  582. f:close()
  583. return true
  584. end
  585. end
  586. function scite_CurrentFile()
  587. return props['FilePath']
  588. end
  589. -- (Nicolas)
  590. if GTK then
  591. function scite_DirectoryExists(path)
  592. local result = os.execute('test -d "'..path..'"')
  593. if result == -1 then return true end -- FIX: why this return -1 on SciTE 2.2.5/Ubuntu?
  594. return result == 0
  595. end
  596. else
  597. -- what is the Win32 equivalent??
  598. function scite_DirectoryExists(path)
  599. return true
  600. end
  601. end
  602. function split(s,delim)
  603. res = {}
  604. while true do
  605. p = find(s,delim)
  606. if not p then
  607. append(res,s)
  608. return res
  609. end
  610. append(res,sub(s,1,p-1))
  611. s = sub(s,p+1)
  612. end
  613. end
  614. function splitv(s,delim)
  615. return unpack(split(s,delim))
  616. end
  617. local idx = 10
  618. local shortcuts_used = {}
  619. local alt_letter_map = {}
  620. local alt_letter_map_init = false
  621. local name_id_map = {}
  622. local function set_command(name,cmd,mode)
  623. local _,_,pattern,md = find(mode,'(.+){(.+)}')
  624. if not _ then
  625. pattern = mode
  626. md = 'savebefore:no'
  627. end
  628. local which = '.'..idx..pattern
  629. props['command.name'..which] = name
  630. props['command'..which] = cmd
  631. props['command.subsystem'..which] = '3'
  632. props['command.mode'..which] = md
  633. name_id_map[name] = 1100+idx
  634. return which
  635. end
  636. local function check_gtk_alt_shortcut(shortcut,name)
  637. -- Alt+<letter> shortcuts don't work for GTK, so handle them directly...
  638. local _,_,letter = shortcut:find('Alt%+([A-Z])$')
  639. if _ then
  640. alt_letter_map[letter:lower()] = name
  641. if not alt_letter_map_init then
  642. alt_letter_map_init = true
  643. scite_OnKey(function(key,shift,ctrl,alt)
  644. if alt and key < 255 then
  645. local ch = string.char(key)
  646. if alt_letter_map[ch] then
  647. scite_MenuCommand(alt_letter_map[ch])
  648. end
  649. end
  650. end)
  651. end
  652. end
  653. end
  654. local function set_shortcut(shortcut,name,which)
  655. if shortcut == 'Context' then
  656. local usr = 'user.context.menu'
  657. if props[usr] == '' then -- force a separator
  658. props[usr] = '|'
  659. end
  660. props[usr] = props[usr]..'|'..name..'|'..(1100+idx)..'|'
  661. else
  662. local cmd = shortcuts_used[shortcut]
  663. if cmd then
  664. print('Error: shortcut already used in "'..cmd..'"')
  665. else
  666. shortcuts_used[shortcut] = name
  667. if GTK then check_gtk_alt_shortcut(shortcut,name) end
  668. props['command.shortcut'..which] = shortcut
  669. end
  670. end
  671. end
  672. -- allows you to bind given Lua functions to shortcut keys
  673. -- without messing around in the properties files!
  674. -- Either a string or a table of strings; the string format is either
  675. -- menu text|Lua command|shortcut
  676. -- or
  677. -- menu text|Lua command|mode|shortcut
  678. -- where 'mode' is the file extension which this command applies to,
  679. -- e.g. 'lua' or 'c', optionally followed by {mode specifier}, where 'mode specifier'
  680. -- is the same as documented under 'command.mode'
  681. -- 'shortcut' can be a usual SciTE key specifier, like 'Alt+R' or 'Ctrl+Shift+F1',
  682. -- _or_ it can be 'Context', meaning that the menu item should also be added
  683. -- to the right-hand click context menu.
  684. function scite_Command(tbl)
  685. if type(tbl) == 'string' then
  686. tbl = {tbl}
  687. end
  688. for i,v in pairs(tbl) do
  689. local name,cmd,mode,shortcut = splitv(v,'|')
  690. if not shortcut then
  691. shortcut = mode
  692. mode = '.*'
  693. else
  694. mode = '.'..mode
  695. end
  696. -- has this command been defined before?
  697. local old_idx = 0
  698. for ii = 10,idx do
  699. if props['command.name.'..ii..mode] == name then old_idx = ii end
  700. end
  701. if old_idx == 0 then
  702. local which = set_command(name,cmd,mode)
  703. if shortcut then
  704. set_shortcut(shortcut,name,which)
  705. end
  706. idx = idx + 1
  707. end
  708. end
  709. end
  710. -- use this to launch Lua Tool menu commands directly by name
  711. -- (commands are not guaranteed to work properly if you just call the Lua function)
  712. function scite_MenuCommand(cmd)
  713. if type(cmd) == 'string' then
  714. cmd = name_id_map[cmd]
  715. if not cmd then return end
  716. end
  717. scite.MenuCommand(cmd)
  718. end
  719. local loaded = {}
  720. local current_filepath
  721. -- this will quietly fail....
  722. local function silent_dofile(f)
  723. if scite_FileExists(f) then
  724. if not loaded[f] then
  725. dofile(f)
  726. loaded[f] = true
  727. end
  728. return true
  729. end
  730. return false
  731. end
  732. function scite_dofile(f)
  733. f = extman_path..'/'..f
  734. silent_dofile(f)
  735. end
  736. function scite_require(f)
  737. local path = lua_path..dirsep..f
  738. if not silent_dofile(path) then
  739. silent_dofile(current_filepath..dirsep..f)
  740. end
  741. end
  742. if not GTK then
  743. scite_dofile 'scite_other.lua'
  744. end
  745. if not scite_DirectoryExists(lua_path) then
  746. print('Error: directory '..lua_path..' not found')
  747. return
  748. end
  749. function load_script_list(script_list,path)
  750. if not script_list then
  751. print('Error: no files found in '..path)
  752. else
  753. current_filepath = path
  754. for i,file in pairs(script_list) do
  755. silent_dofile(file)
  756. end
  757. end
  758. end
  759. -- Load all scripts in the lua_path (usually 'scite_lua'), including within any subdirectories
  760. -- that aren't 'examples' or begin with a '_'
  761. local script_list = scite_Files(lua_path..dirsep..'*.lua')
  762. load_script_list(script_list,lua_path)
  763. local dirs = scite_Directories(lua_path,'^_')
  764. for i,dir in ipairs(dirs) do
  765. load_script_list(scite_Files(dir..dirsep..'*.lua'),dir)
  766. end
  767. function scite_WordAtPos(pos)
  768. if not pos then pos = editor.CurrentPos end
  769. local p2 = editor:WordEndPosition(pos,true)
  770. local p1 = editor:WordStartPosition(pos,true)
  771. if p2 > p1 then
  772. return editor:textrange(p1,p2)
  773. end
  774. end
  775. function scite_GetSelOrWord()
  776. local s = editor:GetSelText()
  777. if s == '' then
  778. return scite_WordAtPos()
  779. else
  780. return s
  781. end
  782. end
  783. --~ scite_Command 'Reload Script|reload_script|Shift+Ctrl+R'
  784. --~ function reload_script()
  785. --~ current_file = scite_CurrentFile()
  786. --~ print('Reloading... '..current_file)
  787. --~ loaded[current_file] = false
  788. --~ silent_dofile(current_file)
  789. --~ end
  790. --~ require"remdebug.engine"
  791. --~ remdebug.engine.start()