A LiveCode Shell

by David Williams on December 10, 2014 5 comments

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.

2014-12-10 11_55_44-MTPuTTY (Multi-Tabbed PuTTY)

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:

2014-12-10 12_44_57-MTPuTTY (Multi-Tabbed PuTTY)

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

 

David WilliamsA LiveCode Shell

5 comments

Join the conversation
  • Peter - December 11, 2014 reply

    Might be worth extending isCommand to check for +x 😉

    David Williams - December 11, 2014 reply

    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 reply

    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 reply

    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.

Join the conversation

*