How to make writing LSL scripts easier

From Second Life Wiki
Revision as of 11:15, 5 January 2014 by Ratany Resident (talk | contribs) (initial commit)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search

This article is currently being worked on.


How to make writing LSL scripts easier

This article is currently being worked on.


About

This article is about tools you can use to make writing LSL scripts easier and tries to explain how to combine and use them for this very purpose. These tools particularly involve a decent editor (emacs) and a preprocessor (cpp).


After I wrote my first wiki article which mentions using a preprocessor to create LSL scripts, a friend of mine said that for a change, I had written something readable. He then asked me to write an article about how to use cpp as preprocessor.

If I had told him that I wrote the article, like everything else, in emacs, he might have thought differently because he seems to imagine that text must not be written in easily readable monospace fonts but be overloaded with distracting proportionality, pictures and colours. Insofar overloading the text supports its purpose without making it ambiguous or confusing, I probably have to agree with him. You can do that with emacs, too.

You also can simply run 'cpp -P your-script.lsl'. It´s basically all you need to use cpp as a preprocessor for LSL scripts --- and probably not what you want. I don´t mess with pictures in emacs and use a tool like gimp for that. Always use the right tools if you can, and use good ones.

So you need tools, and an article about how to use cpp as a preprocessor for LSL scripts needs to be a bit overloaded to, hopefully, lead its readers to something useful.

Editing this page

This article is written in emacs, and when I update it on the wiki, I edit the whole article, delete everything and paste the new version in. That´s simply the easiest and most efficient way for me.

Unfortunately, this means that your modifications may be lost when I update the article and don´t see them.

Please use the "discussion" page of this article to post contributions or to suggest changes so they can be added to the article.

Tools

Editor

To write scripts, you do need an editor. All sl clients I´ve seen have one built in, and it´s the worst editor I´ve ever seen. Fortunately, you don´t need to use it.

You can use any editor you like. You probably want an editor that at least gets the indentations right and has useful functions like 'indent-region', 'sort-lines', 'goto-matching-fence' etc., lets you define macros, highlights matching brackets, supports code-folding and tags, does customizable syntax highlighting, lets you edit several files at once, restores them when you restart the editor and has something like 'auto-revert-mode' so you can read the debugging messages of your scipts which they write into your chat.txt --- plus lots of other things like regexp search/replace that don´t come to mind at the moment.

You do not use the built-in editor for anything but replacing the scripts you have been working on in your favourite editor and to look at the error messages that may appear when you replaced a script.

This has several advantages like:


  • You can use a decent editor!
  • You have the sources of all your scripts safely on your own storage system.
  • Your work doesn´t get lost when your sl client crashes or when you get logged out or when "the server experiences difficulties" again.
  • You don´t need to be logged in to work on your scripts.
  • You can preprocess and postprocess and do whatever else you like with your scripts before uploading them.
  • You can share your scripts and work together with others because you can use tools like git and websites like github. (Even when you don´t share your scripts, git is a very useful tool.)
  • How fast you can move the cursor in the editor does not depend on the FPS-rate of your sl client.
  • You can use fonts easier to read for you, simply change the background and foreground colours and switch to the buffer in which you read your emails or write a wiki article like this one ...
  • Though it doesn´t crash, a decent editor has an autosave function and allows you to restore files in the unlikely case that this is needed.
  • And yes, you can use a decent editor :)


Automatically replacing Scripts

The editor built into sl clients comes with buttons like to save and to reset the script which is being edited. There is also a button labled "Edit". As the label of this button suggests, the button is for editing the script. The built-in editor is not for editing the script, though it´s not impossible to kinda use it for that.

Open a script in your sl client and click on the edit button of the built-in editor. You might get an error message telling you that the debug setting "ExternalEditor" is not set. Set this debug setting so that your favourite editor is used, and click on the edit button again.

\picture edit button

\picture external editor setting

Your favourite editor should now start and let you edit the script. What actually happens is that your sl client saves the script which you see in the built-in editor to a file. Then your sl client starts whatever you specified in the debug setting as "external editor". To tell your favourite editor which file the script has been saved to, the place holder %s is used with the debug setting "ExternalEditor".

Once the script has been saved to a file, your sl client monitors the file for changes. When the file changes --- which it does when you edit and then save it with your favourite editor --- your sl client replaces the script in the built-in editor is with the contents of the file.

This is nice because you could write a new script while you are offline. When you are ready to test the script, you could log in with your sl client, build a box, create a new script in the box, open the script, click on the "Edit" button, delete the contents of the new script in your favourite editor, insert the script you have written and save it. Your sl client would notice that the file changed and put it into the built-in editor. It would let the sl server compile the script and show you the error messages, if any. If your script compiles and works right away, you´re done --- if not, you can use the built-in editor to check the error messages and your favourite editor to make changes as needed.

This becomes awkward when you have a lot of scripts: To replace each script with the new version, you need to open it, click the "Edit" button, delete the script in your favourite editor and save it. In case you get error messages and need to change your script, you have to go back to your source, modify it and replace it again.

Fortunately, you don´t need to do this. All that´s needed is replacing the file your sl client saved the script to with a new version of the file. You don´t need to use your favourite editor to replace the file. A program or script which is started by your sl client instead of your favourite editor can replace the file for you. It only needs to know which file it must replace the file saved by your client with.

With such a program or script, all you need to do is to open the script in the built-in editor and to click on the "Edit" button. You can easily write such a program or script yourself.

Perl is a programming language very suitable to write this script in. It looks like this:


<lsl>

  1. !/bin/perl


  1. This program is free software: you can redistribute it and/or
  2. modify it under the terms of the GNU General Public License as
  3. published by the Free Software Foundation, either version 3 of the
  4. License, or (at your option) any later version.
  5. This program is distributed in the hope that it will be useful, but
  6. WITHOUT ANY WARRANTY; without even the implied warranty of
  7. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  8. General Public License for more details.
  9. You should have received a copy of the GNU General Public License
  10. along with this program. If not, see
  11. <http://www.gnu.org/licenses/>.


use strict; use warnings; use autodie;

use File::Copy;


if(!($ARGV[0] =~ m/.*\.lsl/)) {

 system("emacsclient", "-nc", $ARGV[0] );
 exit(0);

}


my $table = "../replaceassignments.txt";

open my $script, "<", $ARGV[0]; my $line = <$script>; close $script; chomp $line; $line =~ s!// =!!g; if( ( !($line =~ m/.*\.o/) ) && ( !($line =~ m/.*\.i/) ) ) {

   system("emacsclient", "-c", $ARGV[0], $table);
   exit;

}

$line .= ": "; my $replacementfile = undef; open my $assign, "<", $table; while( <$assign> ) {

 chomp $_;
 if( m/$line/) {
   $replacementfile = $';
   last;
 }

} close $assign;

if( !($replacementfile =~ m/.*\.o/) && !($replacementfile =~ m/.*\.i/) ) {

 system("emacsclient", "-c", $ARGV[0], $table);

} else {

  1. sleep 2;
 $line =~ s/: $//;
 if($line =~ m/.*\.i/) {
   ## insert the file name at the top
   open $assign, ">", $ARGV[0];
   print $assign "// =" . $line . "\n";
   open $script, "<", $replacementfile;
   while( <$script> ) {
     print $assign $_;
   }
   close $script;
   close $assign;
 }
 else {
   ## file name is already in first line
   copy($replacementfile, $ARGV[0] );
 }

} </lsl>


You´ll find this script in the git repository that accompanies this article as projects/bin/replace.pl. What it basically does is simple:


  • look at the first line of the file saved by the sl client the name of which is proivded as a command line argument (via the place holder %s by your sl client)
  • when the line starts with "// =", treat the rest of the line from there as a key
  • search the key in a file that assigns the key to file names
  • when the key is found in the file with the assignments, extract the name of the file to replace the file saved by the sl client with from the entry in the assignment file
  • replace the file saved by the sl client with the file the name of which is specified in the file with the assignments
  • when the key is not found in the file with the assignments, start the external editor to edit the file that was saved by the sl client and to edit the file with the assignments


Entries in the file with the assignments are so-called key-value pairs. They look like this:


<lsl> example-script.o: /path/to/example-script.o foobar-script.o: /path/to/foobar-script.o </lsl>


This means when you have a script in the built-in script editor like


<lsl> // =example-script.o

default { state_entry() { Say(0, "test"); } } </lsl>


and click on the "Edit" button of the built-in script editor, the script will automatically be replaced with the contents of the file "/path/to/example-script.o".

To make this work, you need to:


  • change the debug setting "ExternalEditor" so that above perl script is started instead of your editor
  • create the file with the assignments
  • make sure that your script starts with the line "// =example-script.o"
  • ensure that the perl script is able to start your favourite editor


The "favourite editor" in this case is emacs, and emacsclient is started by the perl script to make use of an existing emacs session. You can modify the perl script so it starts your favourite editor.

Emacs

Emacs comes with syntax highlighting many programming languages. LSL syntax highlighting modes for emacs are available.

In case you don´t want to use emacs, you may want to check out thispage about editors. For emacs, you could use Emacs_LSL_Mode.

You can find a mofied version of lsl-mode in the git repository that accompanies this article as emacs/lsl-mode.el.

That version has mainly been modified to be used with a file I named "lslstddef.h", which takes this article to the next section:

A Preprocessor

The Wikipedia article about preprocessors gives an interesting explanation of what a preprocessor is and provides an overview.

For the purpose of making it easier to write LSL scripts, a preprocessor as is used with C (and C++) compilers is a very useful tool.

The particular preprocessor I´m using is called "cpp" and comes with GCC.

What cpp does

Cpp can do a couple things that make it easier to write LSL scripts. Cpp enables you to:


  • automatically include files into others
  • define and use macros
  • use conditionals


That doesn´t sound like much, yet these are rather powerful features. Some of the advantages that come with these features are:


  • Code becomes re-usable by including it into many different LSL scripts.
  • Scripts become much easier to modify and to maintain because instead of having to change parts of the code in many places, you can change a macro definition at one single place.
  • Scripts may become less prone to bugs and errors because code is easy to re-use and easier to modify and to maintain.
  • You may write scripts that use less memory because instead of using variables as constants, you can use so-called defines. This may allow you to do something in one script rather than in two and save you all the overhead and complexity of script-intercommunication.
  • Macros can be used instead of functions, which may save memory and can help to break down otherwise unwieldy logic into small, handy pieces which are automatically put together by the preprocessor.
  • Using macros can make the code much more readable, especially with LSL since LSL is often unwieldy in that it uses lengthy function names (like llSetLinkPrimitiveParamsFast(), ugh ...) and in that the language is very primitive in that it doesn´t even support arrays, let alone user-definable data structures or pointers or references. It is a scripting language and not a programming language.
  • Using macros can make it much easier to write a script because you need to define a macro only once, which means you never again need to figure out how to do what the macros does and just use the macro.
  • Frequently used macros can be gathered in a file like "lslstddef.h" which can be included into all your scripts. When you fix a bug in your "lslstddef.h" (or however you call it), the bug is fixed in all your scripts that include it with no need to look through many scripts to fix the very same bug in each of them at many places in their code.
  • Macros can be used for frequently written code snippets --- like to iterate over the elements of a list --- and generate several lines of code automatically from a single, easy to read line in your source.
  • Conditionals can be used to put code which you have in your source into the resulting LSL script depending on a single setting or on several settings, like debugging messages that can be turned on or off by changing a single digit.
  • Using conditionals makes it simple to create libraries for particular applications and to use only those functions from the library which are needed by a particular script.
  • Macros and defines in your sources only make it into a script when they are actually referred to.