PageRenderTime 29ms CodeModel.GetById 2ms app.highlight 20ms RepoModel.GetById 1ms app.codeStats 0ms

/extman/extman.lua

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