> I came up with a solution, but it seems a bit of a hack:
> ...
> props["command.49.*"] = command
> props["command.mode.49.*"] = "subsystem:shellexec"
> -- trigger user command #49
> scite.MenuCommand(1149)
It is a bit of a hack and this may break in the future.
> It seems to work well, but It feels rather brittle (I don't know if
> there could be some unwanted interactions or subtle problems).
> Is there a direct way to feed commands to SciTE execution subsystems
> without this sort of tricks?
There were some proposals for better functionality in this area but
it is complex as it involves multiple threads and/or tasks.
Neil
> function RunFoo()
> local command = [[foo.exe dummy1 dummy2]] -- command line usually
> fed to os.exec
> -- redefine user command #49
> props["command.49.*"] = command
> props["command.mode.49.*"] = "subsystem:shellexec"
> -- trigger user command #49
> scite.MenuCommand(1149)
> -- restore the original definitions
> props["command.mode.49.*"] = nil
> props["command.49.*"] = nil
> end
This is an interesting trick.
But there are problems. Fixed them in scite-ru <http://code.google.com/p/scite-ru/issues/detail?id=53>
You can use shell.exec <http://scite-ru.googlecode.com/svn/trunk/pack/tools/LuaLib/shell.html#exec>
It's easier and safer.
--
mozers
<http://scite.net.ru>
Oh, it does get tricky! So when I needed this kind of functionality I
wrote a little Lua extension in C to do the job.
If you look at scite-debug.zip from
http://luaforge.net/frs/?group_id=327
you'll see a spawner-ex.dll.
The extman.lua shows how to load this and use its version of popen if available.
-- 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
Then you have spawner.popen, which doesn't flash that irritating box.
This dll also provides a means to capture processes interactively,
that is effectively a popen2. I needed this to spawn debug processes
- this does get a bit involved because you have to pump the output of
the process asynchronously back into SciTE lua, using a callback.
BTW, even on GTK I found the stock io.popen to cause Glib memory
crashes sometimes - this is why spawner.popen is also defined for
Unix.
steve d.
Ah, I'm lookiing at the code and I can see that it has a little
problem with quoted arguments, I'll fix that.
> P.S.: I skimmed through the source code for spawner-ex.dll and I saw
> it registers a bunch of functions which seem quite useful. Is there
> some specific documentation on their usage available (even some sort
> of bare API docs would do, such as basic usage, parameters in,
> parameters out, return values, limits)?
My bad, always forgot about documentation ;) You correctly note that
it really should be called spawner.dll and then require() will work
out of the box.
out = spawner.popen(cmd) -- does prepend cmd.exe /c (depends on COMSPEC)
This can be useful because you can both write to a process and then
read from it.
inf,out = spawner.popen2(cmd)
These are file objects, but I couldn't work out how to make them
actual standard Lua file objects. So this DLL basically copies code
from the Lua liolib.c implementation. You can write(), read() and
lines() also works.
However, it does block, which is not a cool thing with a GUI app like SciTE.
So we have the spawner object. For instance, when running a debugger subprocess:
spawner_obj = spawner.new(dbg_cmd)
spawner_obj:set_output('ProcessChunk')
spawner_obj:set_result('ProcessResult')
spawner_obj:run()
This returns immediately; any output from the process is passed to a
global SciTE function ProcessChunk as a string, and the final result
will go to ProcessResult (receives the result code as a string.) This
happens asynchronously in the main GUI thread so SciTE is not
affected.
spawner_obj:write() is available for speaking to the captured process,
just passes a string.
This is how scite-debug manages to run GDB and the Python and Lua
debuggers in the background.
steve d.
> Ah, I'm lookiing at the code and I can see that it has a little
> problem with quoted arguments, I'll fix that.
>
>
Ok, thanks.
> [snip (lots of hints)]
>
>
Thank you again! Lots of stuff to ponder about!
Best Regards
Lorenzo
Mozers:
shell.dll works well (no extensive testing done, though). I still can't
find licensing info even in the zip you sent me by PM. Is it public
domain? Or MIT, like Lua, or GPL/LGPL?.
Mozers & Steve:
Both libraries (shell.dll & spawner.dll) inject themselves into Lua's
global namespace (IIRC this practice has been discussed in Lua's mailing
list lately and deprecated in upcoming Lua 5.2).
For my purposes It would be much better if this didn't happen, so I'd
like to try and hack the source to make those libraries only return a
table when "required" (that's why I also need to know the licensing term
for shell.dll source).
Best Regards,
Lorenzo
You are welcome to make any modifications (it's licensed under the
same terms as ScITE), although I think people get a little overexcited
about changes to the global Lua table. What we should be able to
assume is that 'local mod = require 'package.mod' makes mod to be the
module, and that there is then a global 'package.mod' containing the
module. Some modules don't behave so nicely (e.g mod is just true)
and these are the problem.
The general problem of global namespace pollution (to use the C++
term) in Lua is probably better solved by your environment performing
static analysis on the code, like David Manura's lua-inspect. He
should be announcing his SciTE plugin soon.
steve d.
Source code is absolutely free. No licensing restrictions.
I.e. you can freely modify it and use it anywhere.
If you share with us a improved code it will be good.
If you mention the source it would be just wonderful.
--
mozers
<http://scite.net.ru>
> although I think people get a little overexcited
> about changes to the global Lua table. What we should be able to
> assume is that 'local mod = require 'package.mod' makes mod to be the
> module, and that there is then a global 'package.mod' containing the
> module. Some modules don't behave so nicely (e.g mod is just true)
> and these are the problem.
>
Mmmh. I'm not an extremist about globals (regardless of language), but I
still try to avoid them like plague, except for quick and dirty
throw-away scripts/programs.
In the years I've grown a sort of itch about them: whenever the code I'm
writing grows longer than, say, about 20-30 lines, I feel an urge to
make any symbol "as local as possible" :-) .
For the same reason I feel rather disturbed when external code has
"unexpected" side effects (well, with Lua modules this is not so
"unexpected"... :-) ). I highly value the principle of least surprise
and unknown globals popping up from almost nowhere is not something I
would want to care about!
I'm not really an expert of Lua, but I don't see the _need_ for a module
to make its "symbols" directly accessible as globals (or as a global
table). It's Just a convenience, but if the module returned the "symbol"
table (as you point out), there would be no need to put anything in _G
(or am I missing something?!?). This is maybe more troublesome with
modules loaded indirectly: in this case I may not even know that
something is being put in _G (the module I require might behave
"nicely", but require in turn another module that doesn't)! (I hope I'm
not being too much OT for this list - maybe all this should be moved to
Lua mailing list?)
Best Regards,
Lorenzo
Believe me, the lua list is full of this discussion at the moment ;)
But globals with SciTE Lua are unavoidable, e.g OnKey etc callbacks.
One just has to be awake...
steve d.
Best Regards,
Lorenzo