For some time, I have been wishing that I could have some kind of command-line oriented functionality to LiveCode, beyond writing scripts with LiveCode Server. What if I could pipe things directly to it, or run it as an interactive shell? Being able to very quickly make use of the text handling in LiveCode would be extremely handy for certain command line oriented types of tasks. Alas, this is not possible with LiveCode or LiveCode Server as it currently stands. However, after some thought, I concluded that it should be possible to put together a script to provide this functionality.
Click to Zoom
After some time, I had produced a script which operates as a simple shell type interface. But how does it work? It’s actually fairly simple. The script is a LiveCode Server script, designed to be invoked via command line. When it starts up, it reads in the options passed to it on the command line to determine how it should behave. The options passed to it are in the $x variables, starting at $0. $# tells us how many were passed.
#!/usr/local/bin/livecode-server
## substitute this with the path to your livecode server executable
## array for storing the options passed to this program
local sOpts
## load options
repeat with x = 0 to ($# – 1)
do “put $” & x && “into tReadOpt”
if char 1 of tReadOpt is “-” then
repeat with y = 2 to the number of chars in tReadOpt
put char y of tReadOpt into sOpts[(the number of lines in the keys of sOpts + 1)]
end repeat
else
put tReadOpt into sOpts[(the number of lines in the keys of sOpts + 1)]
end if
end repeat
There are currently two modes: interactive and execute. We can also pass the -p option to tell it to expect data to be piped to it, and read it into a variable called ‘input’. If we pass it the -e option it starts up in execute mode, and expects you to have specified a command for it to run. It then exits after running the command. Usage for this would be like “lcsh -e ‘put hello world’”. Otherwise, it starts up in interactive mode.
## read from pipe
if optEnabled(“p”) then
read from stdin until EOF
put it into input
end if
## get command from last command line option and execute it, then quit
if optEnabled(“e”) then
do sOpts[(the number of lines in the keys of sOpts)]
put return
quit
end if
## interactive mode
repeat
put “lcsh[” & the folder & “]# “
read from stdin for 1 line
put it into tCommand
if isCommand(tCommand) then
put shell(tCommand)
else
try
do tCommand
catch pError
put “Error:” & return
put pError
end try
end if
put return
end repeat
Execute mode simply takes the last command line option and uses do on it, then quits. Interactive mode reads 1 line from stdin at a time (i.e. it reads 1 typed line by the user at a time) and then determines what should be done with it. It uses the isCommand function to check the $PATH environment variable (which contains all of the directories which should be looked in for executable programs) to see if what was entered was a utility that is already installed, such as the standard Linux utilities. If it was, it uses shell() to execute the entered command. Otherwise, it uses the do command to execute it as normal LiveCode code, catching any generated errors so that they can be displayed without causing the program to exit:
## checks to see if the first word is a command in $PATH
function isCommand pCommand
set the itemDel to “:”
put the folder into tFolder
put false into tIsCommand
repeat for each item tDir in $PATH
set the folder to tDir
if word 1 of pCommand is among the lines of the files then put true into tIsCommand
end repeat
set the folder to tFolder
return tIsCommand
end isCommand
There is also the optEnabled function that was referenced above. This checks to see if the program was loaded with a specific option enabled:
function optEnabled pOpt
repeat for each key tKey in sOpts
if sOpts[tKey] is pOpt then return true
end repeat
return false
end optEnabled
This is quite clunky and has many, many problems – for example, there’s no ability to pipe the output of some LiveCode to another program in interactive mode, and you can’t open another program that requires interaction. However, I think that with a lot more work, this could become quite a robust and useful tool. It already provides some very handy functionality in it’s current state, namely that I can pipe to it for text parsing:
Click to Zoom
I will probably keep chipping away at this until I can use it as my primary command line interface. You can get the full code here: http://jasminedavid.on-rev.com/lcsh.txt
5 comments
Join the conversationLiveCode - December 10, 2014
LiveBlog: Can LiveCode be an interactive shell? You be the judge! http://t.co/mbkk1rmzZT #CreateItWithLiveCode
Peter - December 11, 2014
Might be worth extending isCommand to check for +x 😉
David Williams - December 11, 2014
Yeah, it definitely needs to check for permissions, and also anything starting with / or ./ should be interpreted as a command. It should also use open process rather than shell(), as this could be used for communication with the process rather than just executing it and exiting. I think these will be some of the next things to implement.
Greg Miller (Pink) - December 17, 2014
This could definitely be one of the most useful bits of help for me right now… Working on a new linux server, it’s not to have command line access to the wonder that is Livecode.
Thanks!
Geoff Macumber - December 17, 2014
Hi guys,
I have used a little of this kind of technique for an application under windows 8. The only problem I have so far is to stop the stack displaying the screen. I haven’t devoted much time to it but as an interim drop the screen to the task bar.
It’s pretty neat though…
Rgds Geoff.