Cameleon
release 1.1
Documentation and user's manual

Maxence Guesdon
(with Dimitri Ara)
Copyright © 2002 Institut National de Recherche en Informatique et en Automatique



Foreword

This manual documents the release 1.1 of the Cameleon environment. After a short introduction, it explains the installation. Then each tool is described, and the last chapter describes the other libraries included in Cameleon.

License

The Cameleon environment is copyright © 2002 Institut National de Recherche en Informatique et en Automatique (INRIA). INRIA holds all ownership rights to Cameleon.
The Cameleon environment is open source and can be freely redistributed. See the file LICENSE in the distribution for licensing information. The present documentation is distributed under the same conditions.

Chapter 1  Introduction

Cameleon aims to become an integrated development environment for Objective-Caml, and eventually other languages. Its main features are :

Chapter 2  Installation

If you install Cameleon from the sources, follow the explanations below. If you install from a pre-compild package, you can ignore this part.

Unpack the source archive with the following command :
tar xfz cameleon_1_1.tar.gz
This will create a cameleon-1.1 directory, called the root directory. Change to this directory.

Note for the impatient: If you're used to install procedures, this one is not original, and you can run the following commands to install Cameleon :
./configure [--includedir=/absolute/path/to/compiled/ocaml/sources]
    (use the --includedir option if you have the compiled sources \\
     of OCaml somewhere)
make depend
make
make doc

make install

2.1  Pre-requisites

In order to compile, you need to have OCaml 3.06 (or more) and LablGtk 1.2.5 (or more) installed. In order to compile the graphical toplevel and Epeire, you must have the compiled sources of the OCaml compiler somewhere.

2.2  Configuration

Use the ./configure script to configure the sources according to your OCaml installation.

The configure script accepts the following options :
-prefix <dir>
Will make the files to be installed in subdirectories of <dir> instead of in the OCaml directory.

-libdir <dir>
Will make the compiled libraries to be installed in <dir> instead of the cameleon directory in the OCaml library directory.

-bindir <dir>
Will make the executables to be installed in <dir> instead of the bin directory of the prefix directory.

-mandir <dir>
Will make the man pages to be installed in <dir> instead of the man directory of the prefix directory.

--datadir=<dir>
Will use <dir> to store templates, plug-ins and pixmaps, respectively in the templates, plugins and pixmaps directories. The default directory is prefix/share.

--includedir=<dir>
Where <dir> must be the absolute path name to the OCaml compiled sources. Use this option if you want to build the graphical toplevel and Epeire, the graphical debugger, which both need to be linked with a part of the OCaml compiler.

2.3  Compilation

Once the configure script has been run, you can compile Cameleon with the following commands:
make depend
make

Then you should create some documentation files :
make doc

2.4  Installation

Finally, if you have the permission to write in the directories specified to the configure script, the command
make install
will install the executables, libraries, man pages, templates and plugins.

Chapter 3  Report

3.1  Introduction

The Report tool aims to make generation of XML documents from OCaml applications easier. The main idea is to separate the structure of the document from the information computed by the application and placed in the document. For example, in the following document :
<h1>Crepes</h1>
<list>
  <item>flour</item>
  <item>eggs</item>
  <item>sugar</item>
</list>
the document structure is
<h1> </h1>
<list>
  <item> </item>
  <item> </item>
  <item> </item>
</list>
while computed information is “Crepes”, “flour”, “eggs” and “sugar”.

To build our XML document, we must therefore describe its structure as well as the way to fill it with information. Then, at runtime, the application will use this description to generate the final XML document.

In practice, Report allows to graphically describe the document (structure + information), and then to generate OCaml code which uses the Report library. In particular, this library contains a function which computes a document description to produce the final XML document. An important point is that the way to compute the information needed in the document is given in the form of OCaml code.

The Report library as well as the generated code are detailed in 3.2. The description of document and the use of the report tool are explained in 3.3.

3.2  The Report library

3.2.1  Types

The Report module defines the types used to describe a document.
(** A report element. *)
type 'a report_ele =
  | Leaf of (unit -> string)
  | Tag of 'a tag
  | List of 'a liste
  | Cond of  'a cond
  | Sub of (unit -> 'a report)

(** A tag. *)
and 'a tag = {
    tag : string ;
    atts : (string * (unit -> string)) list ;
    tag_subs : 'a report_ele list
  } 
    
(** A list of substructures. *)
and 'a liste =
    { list_subs : 'a report_ele list ;
      f : (unit -> 'a list) ;
      mutable current : 'a ;
    }

(** Conditional *)
and 'a cond =
    { cond : unit -> bool ;
      subs_then : 'a report_ele list ;
      subs_else : 'a report_ele list ;
    } 

(** A report description is a list of report elements. *)
and 'a report = {
    rep_eles : 'a report_ele list ;
  } 
The type report_ele is the type of the tree nodes : The document example of the introduction could be described by :
let rec report  = 
  ({
   rep_eles = [
     Tag { tag = "h1" ; atts = [] ; 
           tag_subs = [
             Leaf (fun () -> "Crepes");
           ] } ;
     Tag { tag = "list" ; atts = [] ; 
           tag_subs = [
             ( let rec ing = 
                 { f = (fun () -> ing_of_recipe "Crepes") ; 
                   current = (Report.coerce 0) ; 
                   list_subs = [
                     Tag { tag = "item" ; atts = [] ; 
                           tag_subs = [ Leaf (fun () -> ing.current.ing_name) ] }
                   ] }
                in
                List (Report.coerce ing))
           ] 
          }
    ]
   } : int report)
The call to Report.coerce is necessary to force the type but type constraints are already satisfied (notably the use of the current field) at this point.

As we can see, this structure can quickly become a pain to define and read. To solve this problem, the report tool allows to graphically define the document description and generate the OCaml code of this structure.

Moreover, the report value could have had parameters ; this is a way to parametrize the final XML document.

3.2.2  Functions

The Report module contains the following functions :
(** Coerce report elements. *)
val coerce : 'a -> 'b

(** Compute a report and print it to the given formatter. *)
val compute : ?html: bool -> Format.formatter -> 'a report -> unit

(** Compute a report and print it in a file. *)
val compute_file : ?html: bool -> string -> 'a report -> unit
The coerce function is used to insert a 'a report_ele into the node of a 'b report_ele, when 'a cannot be used as 'b. This function must only be used for this purpose, as in the example above.

The compute function takes a formatter and a document description and computes this description to generate the final XML document in the given formatter. The html optional parameter allows not to close some tags (like br) to generate HTML compliant documents.

The compute_file function acts like compute but writes in the given file instead of a formatter.

3.3  The report and report.gui tools

The report.gui tool allows to describe a document (structure + code to fill it with information), as well as the parameters of this document (these parameters become parameters of the report value in the code example in 3.2). The document is describe through a graphical user interface with a tree oriented view.

The report tool generates the OCaml code of the document description, using the types defined in the Report library (cf. 3.2).

Here is the report command usage : report [options] description_file
The following options are supported :
-gen
Generate the OCaml code for the document described in the given file. The code is generated in a file whose name is function of description_file. If description_file has an extension, the generated file as the same name with the extension replaced by .ml. If description_file has no extension, then the generated file has the same name, with the .ml extension appended.

-o file
Generate the OCaml code in file file, instead of the default file, when the -gen option is given.

Chapter 4  Zoggy

4.1  Introduction

Zoggy is a graphical interface builder for LablGtk, the OCaml/GTK library. Zoogy allows you to graphically build your windows and boxes, then generate OCaml code which creates these windows and boxes.

We explain the use of Zoggy as in a tutorial, through two examples. The “Hello world” example presented in section 4.3 is a simple first example of the use of Zoggy. A more complex example is presented in section 4.4.

4.2  The templates file

When Zoggy is launched, it loads the ~/.zoggy/templates file. This file is a regular Zoggy file which can be edited with Zoggy. Each entity in this file then appears in the Template menu of the entity edition window. Selectionning a template insert it in the current entity. So you can define your templates by editing your ~/.zoggy/templates file, then use these templates when you use Zoggy to edit other files.

4.3  The “Hello world” example

This example is a simple window with a button and a label. Clicking on the button will display the text “Hello world” in the label. The final window is displayed on figure 4.3.



Figure 4.1: The “Hello world” example window



The development process consists of the following steps:
  1. Describing the window with Zoggy,
  2. Generating code from the window description,
  3. Adding code which uses the generated code,
  4. Compiling and executing.

4.3.1  Describing the window

We will describe the window in the file guibase.zog. This is done by the following command:
zoggy guibase.zog
The window of figure 4.3.1 appears. This window is used to define entities. Each entity will become a class in the generated code. The entity parameters will become class parameters. For each entity, a hierarchy of widgets is defined, as explained later. Each new instance of a class will build the widgets described in the entity from which the class was generated.



Figure 4.2: The Zoggy main window



We need to add a new entity, corresponding to the window we want to build. The Entity/Add entity command pops up a window where the entity name can be given. We'll call it hello. After a click on the “Ok” button, the main window now contains the new entity.

Click on the hello entity in the main window to open it. The entity window appears, in which we can edit the widgets of the entity. It is composed of For the moment, the widget hierarchy is empty, so the first thing to do is to create a window: click on the “window” button in the palette. Since buttons are ordered in the widget alphabetical order (top to bottom and left to right), this button is at the end.

Two things occur: Now click on the new item in the tree to edit the properties of the window. The “Name” field contains the OCaml identificator which will be used for the widget in the code of the generated class. If it starts with a '_', then this widget will not appear in the class interface (but it will still be built for each new instance of the class). Rename this widget to win.

Under the “Name” field, the properties of the window appear. For each property, its name, its value, and the OCaml type of its value are displayed.

The value can be changed, but in the end, it must be valid OCaml code of the correct OCaml type.

For properties with integer values, -1 means “no value” (or “default value”).

Some properties have values of a variant type. In this case, a value among the possible ones can be selected in the associated combo widget, but OCaml code can still be used instead, to compute the value at execution. In such a case, the preview will no be relevant for this property, since the value will only be known at execution.

Here we will change the title of our window : set the “title” value to “Hello world”. Note that the double quotes are important since this must be correct OCaml code of type string.

You can see the preview window change as you modify the value.

Now we must add a vbox in our window, which will contain one label and one button. Click on the “vbox” button in the palette, select it in the tree and rename it to vbox. Then click on the “label” button in the palette to add our label widget. Select it in the tree, rename it to wlabel, and set the “text” property to “Nothing yet”.

As you added the widgets and changed properties of the label, you may have noticed that the size of the window changed too. That's because it adjusts itself to the widget it contains. When we set the text of the label widget, this widget needed mode space, so its parent widget (the vbox) needed more space and the window grew. This behaviour can be changed with the properties “allow_shrink”, “allow_grow” and “auto_grow” of the window.

Now we must add a button to the vbox. Select the vbox item in the widget tree, and click on the “button” button in the palette. A menu appears, click on “with label” to create a button with already a label in it. Enter “Say it” in the window asking you the label text. As you can see in the widget tree, two more widgets have been created, a button and a label in it. The label has a name beginning with '_', to indicate that it won't be in the interface of the generated class. Since we'll need to access the button to specify what must be done when it is clicked, select the button and rename it to wbutton.

Now you can save your description with the File/Save command, and quit Zoggy.

4.3.2  Generating code

The command
camlp4o pa_zog.cma pr_o.cmo -impl guibase.zog > guibase.ml
will generate code to guibase.ml, according to the entities found in guibase.zog.

Let's have a look at the generated code. Our “hello” entity becomes the hello class:
class hello () =
The () parameter is important since without it (and no other parameter) the widgets would be created only once, even with various instances of the class.

Now we can see the creation of the widgets defined in the entity:
  let win =
    GWindow.window ~title:"Hello world" ~allow_shrink:true ~allow_grow:true
      ~auto_shrink:true ~modal:true ()
  in
  let vbox = GPack.vbox ~homogeneous:false ~packing:win#add () in
  let wlabel =
    GMisc.label ~text:"Nothing yet" ~justify:`LEFT ~line_wrap:true ~xpad:2
      ~ypad:2 ~packing:(vbox#pack ~expand:false ~fill:true) ()
  in
  let wbutton =
    GButton.button ~packing:(vbox#pack ~expand:false ~fill:true) ()
  in
  let _5 =
    GMisc.label ~text:"Say it" ~justify:`LEFT ~line_wrap:true
      ~packing:wbutton#add ()
  in
We can find the OCaml code we typed, in some of the properties.

At last, the object is defined as :
  object
    val win = win
    val vbox = vbox
    val wlabel = wlabel
    val wbutton = wbutton
    method win = win
    method vbox = vbox
    method wlabel = wlabel
    method wbutton = wbutton
  end;;
As you can see, the class can be used in two ways: In the next step, we will use the first way to use this generated class.

4.3.3  Using the generated code

Now create a file hello.ml with the following code:
(* Gtk initializations *)
let _ = GMain.Main.init ()

class gui ()=
  object
    inherit Guibase.hello ()
      
    initializer
      (* Exit the event loop when the window is destroyed *)
      ignore (win#connect#destroy GMain.Main.quit);

      (* Display "Hello world" when the button is clicked. *)
      ignore (wbutton#connect#clicked 
  (fun () -> wlabel#set_text "Hello world"));

      (* Show the window *)
      win#show ()
  end

(* Build the window *)
let c = new gui ()

(* Enter event loop *)
let _ = GMain.Main.main ()

4.3.4  Compiling and executing

Now compile with the following command:
ocamlc -o hello -I +lablgtk lablgtk.cma guibase.ml hello.ml
and execute :
./hello

Note that you can compile directly guibase.zog to guibase.cmo and guibase.cmi with the following command:
ocamlc -c -pp "camlp4o pa_zog.cma -impl" -I +lablgtk -impl guibase.zog

Try adding other widgets and changing properties in this first example...

4.4  Example 2

Yet to come.

Chapter 5  DBForge

5.1  Introduction

DBforge is a tool for generating OCaml code to access databases. This code is generated from a schema, described through a graphical user interface.

We explain the use of DBForge as in a tutorial, through a complete example.

We assume that at least one of the following librairies is installed:

5.2  Principle

The tool is based on the following problem : The creation of functions executing SQL queries To solve these problems, we want to To do so, we must have the following information about each colum of each table : The list of tables with the above information for each column is what we call the database schema.

We can note that: So we can have the same interface for accessing different underlying DBMS. The application using this inteface can then be used for each DBMS (if it does not use some DBMS specific functionalities, for example the AUTO_INCREMENT attribute of MySQL).

The DBForge tool can be used to describe such a schema.

It does not allow yet the definition of complex queries and the verification of these queries against the schema.

As an example, we will build a table with several columns, then use the generated code to performs some actions on this table in a database.

5.3  Description of the schema

The description of the schema is made with a graphical editor. A schema is stored in a file. The following command launches the editor on the schema in file base.sch:
dbforge.gui base.sch
The edition window appears. From this window you can edit the tables and columns, and define complex queries which will be encapsulated in functions. (the definition of complex queries is not implemented yet).

Add a table with the menu Table/Add. Enter "foo" for the table name and click on the "Ok" button. The table is then added to our schema. It does not contain any column yet: as you can see when you select the table, the list of columns remains empty.

We'll add three columns to our table. The first will be an integer used as unique identifier, the second will be a float, and the third will be a string.

5.3.1  Column id

Select the table "foo" and use the menu Columns/Add. The column edition window appears. This window contains 4 tabs. The first ("Common") is used to give information common to all DBMS. Each of the other tabs correspond to a target library handled by DBForge: "ODBC" for OCamlODBC, "MySQL" for OCaml-Mysql, et "PostgreSQL" for Postgres.

In the "Common" tab, type the following values in the fields : In each of the remaining tabs, you must indicate the SQL type of the column, whether it's a key (primary key or just a key), and give translations functions to convert SQL values (as strings) to and from OCaml values. Some functions are available in the combo box of each function field, but you can put your own instead.

At last, you can give a default SQL value, which will usually appear in the DEFAULT clause of the column definition.

Here are the values to put in the fields of each tab :

  "ODBC" "MySQL" "PostgreSQL"
"SQL type" integer INT INT8
"Optional key type" primary key primary key primary key
"sql → OCaml" int_of_string Mysql.int2ml int_of_string
"OCaml → sql" string_of_int Mysql.ml2int string_of_int
"Default SQL value"      



Once this is done, click on the "Ok" to add the column to the table “foo”.

5.3.2  Colonne length

In this column we want to store a float. This column is not a key and we may have no value (that is we can have the NULL value).

Here are the values to fill the fields in "Common" with:

Field Value
"Name" length
"OCaml type" float
"nullable" activated
"index" not activated



And in the other tabs:

  "ODBC" "MySQL" "PostgreSQL"
"SQL type" double DOUBLE FLOAT8
"Optional key type"      
"sql → OCaml" float_of_string Mysql.float2ml float_of_string
"OCaml → sql" string_of_float Mysql.ml2float string_of_float
"Default SQL value"      

5.3.3  Colonne comment

In this column we want to store a comment text. This column is not a key and we may have no value (that is we can have the NULL value).

Here are the values to fill the fields in "Common" with:

Field Value
"Name" comment
"OCaml type" string
"nullable" activated
"index" not activated



And in the other tabs:

  "ODBC" "MySQL" "PostgreSQL"
"SQL type" varchar(255) TEXT TEXT
"Optional key type"      
"sql → OCaml" string_of_sqlstring Mysql.str2ml string_of_sqlstring
"OCaml → sql" sqlstring_of_string Mysql.ml2str sqlstring_of_string
"Default SQL value"      



Note: For the “ODBC” tab, we put vachar(255) as SQL type, which is far more restrictive than the TEXT SQL type of the two other tabs, but this way we ensure the portability of the application because this type is standard. However, if we know that the underlying DBMS that the application will use through ODBC supports another SQL type, we can use it. To do so, we can use the field “Other” with the type to use, for example TEXT.

5.3.4  Saving

Now that we have defined our schema, we can save it with the menu File/Save. then quit with the menu File/Quit.

5.4  Code generation

The code generation is performed with one of the following commands:

5.5  Compilation

To compile the generated code, use the following commands, where DBDIR is the directory where the library (OCamlODBC, OCaml-MySQL or Postgres) you want to use is :
ocamlc -c -I DBDIR base.mli
ocamlc -c -I DBDIR base.ml
You can also generate the documentation using ocamldoc :
mkdir htmldoc
ocamldoc -I DBDIR -html -d htmldoc base.mli
Then the documentation is in htmldoc/index.html.

You may have to add -I flags if you referenced other modules in the code in your schema description (OCaml types and translation functions).

5.6  Using the generated code

Type the following code in the file main.ml :
module B = Base
module F = B.Foo

let d = B.connect Sys.argv.(1) Sys.argv.(2)

let _ = 
  try F.create d
  with Failure s -> prerr_endline s

let _ = F.delete d ()

let cpt = ref 0
let _ = 
  while (!cpt <= 1000) do
    (
     if !cpt mod 2 = 0 then
       F.insert d ~id: !cpt  ~length: None ()
     else
       F.insert d ~id: !cpt ~length: (Some (float_of_int !cpt)) 
                  ~comment: (Some (string_of_int !cpt)) ();
     incr cpt
    )
  done

let l = F.select d ()
let _ = List.iter (fun t -> 
  print_int t.F.id;
  print_string "#";
  (match t.F.length with
    None -> print_string "NULL"
  | Some f -> Printf.printf "%f" f);
  print_string "#";
  (match t.F.comment with
    None -> print_string "NULL"
  | Some text -> print_string text);
  print_newline ()) l

let _ = F.drop d
The code above connects to a database, creates the table "foo", deletes all records in it, fills it, reads it, prints the retrieved records and destroys the table.

To compile this example :
ocamlc -o example.x -I DBDIR ocamlodbc.cma base.cmo main.ml

This command works for OCamlODBC. For OCaml-MySQL, you must replace ocamlodbc.cma by mysqlstatic.cma, et by postgres.cma for the Postgres library.

Some other compilation options may be needed (-ccopt -l..., ...).

Next, launch the example this way (if your DBMS is well configured, launched, and if the file ~/.odbc.ini is correct (for the OCamlODBC library)) :
./example.x <user> <database name>
The program should print a thousand records this way:
...
969#969.000000#969
970#NULL#NULL
971#971.000000#971
972#NULL#NULL
973#973.000000#973
974#NULL#NULL
975#975.000000#975
976#NULL#NULL
977#977.000000#977
978#NULL#NULL
979#979.000000#979
980#NULL#NULL
...

Chapter 6  MLChat

6.1  Introduction

MLChat is a simple chat application. It does not use any server, like usual chat applications, making it possible to use on a local network. It supports a conference mode to have a discussion with more than one person. The communication protocol is a text one, so you can communicate with MLChat from applications not written in OCaml.

At last, MLChat comes with a library which can be used to add chat in other OCaml applications. The chat plug-in for Cameleon (see ??) uses this library.

6.2  Configuration

By default, MLChat uses the file ~/.mlchatrc, but you can specify a different configuration file to use with the -c option of the mlchat command.

The configuration window of MLChat is accessed through the File/Options menu. You can specify your id, the port to listen to, the colors, the people you know about, ...

Some of these options can be changed on the command line. Try mlchat -h to get a list of the available options.

6.3  Using MLChat

You launch MLChat with the following command:
mlchat
The main window appears, displaying the list of people you know about. The first time you launch MLChat (or you specify a new configuration file), this list is empty.

You should first set some options, using File/Options. Set your id and some other options. You can add people to your list in the “People” tab or with the File/Add people menu.

Some people can connect to you if they know your host and port. If these people are already in your list, they will appear as connected. If they don't they'll appear in your list as connected but also as temporary people, i.e. people which will disappear next time you launch MLChat. To add these people permanently to your list, use the File/Toggle temp flag for selected people menu. You can also change a permanent friend to a temporary friend with this command.

You can remove people (temporary or not) from your list with File/Remove selected people.

To discuss with one person of your list, select the person and use the File/Open dialog menu. You can also double-click on a person. A chat window appears. You type your message in the text widget at the bottom. Hitting the Enter key sends your message. The text widget at the top of the window shows the messages sent and received. The title of the window indicates the person you're chatting with.

To create a chat room, just select various people in the list and use the File/Open dialog menu. You're prompted for a chat room name, then the chat window appears, with an additionnal button to see who's in the room. The messages you send in this window are sent to all the people in the room.

You can quickly close a dialog window with the CTRL-C shortcut.

When someone sends you a message and your dialog window for this person is closed, the window is automatically open. Meanwhile, if the person sending the message is not in your list of permanent people, the window will pop up only if you set the “popup all” option to true in the configuration window.

People are identified by their hostname and port. So you may have two people in your list referencing to the same person, if you have two different host names for this person.

6.4  The mlchat_say utility

MLChat comes with mlchat_say, a command line utility which can be used to send messages to a MLChat application. Usage:
mlchat_say [-h <host>] [-p <port>] [-i <id>] <message>. You can use it to be warned about events, for example when you receive an e-mail.

6.5  The Mlchat library

Here is the interface of the Mlchat library.

Chapter 7  OCamlCVS

7.1  Introduction

OCamlCVS is a graphical front end for the CVS configuration management utility. It displays the file and directories handled by CVS and offers CVS functionalities through menus. OCamlCVS can also show differences between two revisions, and a merge assistant can be used to resolve conflicts.

OCamlCVS comes with a library which can be used to manipulate CVS handled files in other applications, like it is in Cameleon.

7.2  Usage

You launch OCamlCVS with the following command:
ocamlcvs [dir1] [dir2] ...
Every directory you give on the command line will be a root of the directory tree, on the left part of the main window. If you do not give any directory, the current working directory will be the only root.

When ocamlcvs is launched, the main window appears, with the directory tree on the left, and the file view on the right. The file view shows the files handled by CVS in the selected directory.

The CVS menu offers commands to perform on the selected directory or the selected files. These commands are also available throught contextual menus, when you click with the right button on a directory or a file.

The files in the file view are displayed in different colors, according to their state (Up-to-date, Locally modified, ...).

You can customize the CVS commands that OCamlCVS launches, through your ~/.ocamlcvsrc file. Each line of this file must have the following syntax:
<command>:<options>
For example, to make OCamlCVS pass options to the cvs update command, use the following line:
update :-d -P -A
The commands which can be parametrized are add, commit, remove, status, update.

Please note that you should not use options which modify the output of the CVS command, since this output is parsed by OCamlCVS.

Note: By default, the update command is used with the -d option, and the status command is always used with the -l option.

7.3  The Ocamlcvs library

Here is the interface of the Ocamlcvs library.

Chapter 8  Epeire

8.1  Introduction

Epeire is a graphical interface to the OCaml debugger, ocamldebug.

Its main features are:

8.2  Invocation

To launch Epeire, use the following command:
epeire [options] [-- program [arguments]]
options are detailed below, program is the name of the program to debug, and arguments are its command line arguments.

By default, Epeire uses the $HOME/.epeirerc configuration file to store options, including the program name and its arguments. So you don't have to give the program name and its arguments if they are already in the configuration file.

A configuration file different from the default one can be specified with the -c option. Other options are:
-I <dir>
Add <dir> to the list of include directories, to search for source files.
-history_size <int>
Set the number of times to keep in the history (default is 30).
-checkpoints_on <true|false>
Select whether the debugger makes checkpoints or not (default is true).
-max_checkpoints_count <int>
Set the maximum number of simultaneously live checkpoints (default is 15).
-checkpoints_big_step <int>
Set the number of events between two checkpoints for long displacements (default is 10000).
-checkpoints_small_step <int>
Set the number of events between two checkpoints for small displacements (default is 1000).
Other options can be set with the File/Settings menu. They are automatically saved in the configuration file (the default one or the one specified by the -c option).

8.3  Using Epeire

See the ocamldebug manual, in the OCaml user manual, for an explanation on using the debugger. The graphical interface should be quite intuitive, but here are some hints.

You can show or hide the various windows, either from the configuration window of with the Display menu.

The console can be shown to type commands like in the ocamldebug tool. You type commands in the entry widget, at the bottom of the console and the result appears in the text widget above. You can use the up and down arrows to walk through the history of commands (even the commands launched from menus or by clicking on buttons).

You can record your commands, using the Misc/Record menu. Use the Misc/Stop recording menu to save your recorded commands in a file. You can execute recorded commands with the Misc/Play menu, which lets you select a file from where commands are read. Adding and removing an identificator in the list of identificators (in the value inspector window) are also recorded and played.

The value inspector window lets you add identificators whose value and type will be always displayed for the current time or stack frame. Use the 'Add' and 'Remove' buttons to add or remove an identificator to the list. You can also click on an identificator in the code window to add it to the list. When an identificator is unbound for the current time, no value is displayed. In the list of identificators, you can double-click on an identificator to browse its value at the current time, in a tree-oriented view. A click on the right button opens a menu to print its type and value or browse its value.

The breakpoints window displays the list of breakpoints. You can add a breakpoint The buttons 'Show' and 'Remove' in the breakpoints window lets you respectively show the code where the breakpoint is located and remove a breakpoint.

The call stack window lets you see the current call stack. The 'Show' and 'Select' buttons lets you respectively show the code corresponding to the selected stack frame and select the stack frame to show the values at this frame.

The code window shows the various files, and hilight the line corresponding to the current time or stack frame. From this window you can add breakpoints and add identificators to the list in the value inspector window, as explained above. If a file is not open and you want to see it, for example to add a breakpoint in it, you can open it with the File/Open source file... menu. Then you select a module and the source file of this module is open in the code window.

The Execution menu offers the commands to run the program. The Program management menu gives access to some commands to load and kill the program, and lets you selects the loading mode. Again, see the ocamldebug manual for more information.

Chapter 9  Topcameleon

9.1  Introduction

Topcameleon is a graphical OCaml toplevel. It offers the same possibilities as the ocaml toplevel, and adds the following features: As for the ocaml toplevel, you can also build your own graphical toplevel, including more modules, using the cam-mktop utility (see section 9.4 below).

See the ocaml utility user manual, in the OCaml user manual, for details about using the toplevel.

9.2  Invocation

Topcameleon is launched by the following command:
topcameleon [options] [object-files] [source-file]
The options are the same as the ocaml toplevel, and files in arguments are handled the same was as by ocaml, except that if a source-file is given, Topcameleon does not exit after having evaluated the code in this file, but rather shows the main window with the code in the file still present like if the user had typed it. This way, you can type your code after the loaded code, and when you're satisfied you can save the whole code in one file (by default it is saved in the given source-file). So topcameleon cannot be used as a script interpreter, but it was not developed for such a purpose.

9.3  Using Topcameleon




Figure 9.1: Topcameleon main window.



Figure 9.1 shows the Topcameleon main window. The left pane contains a list of the defined elements (values, types, modules, ...). The second pane shows the selected value, in a tree-oriented way. The right pane is the console, with the result on top and the input text widget at the bottom. The 'Execute' button executes the code in the input widget.

Each time you define a new element, it is added to the list of elements. When you select an element is this list, its value is shown (if it is a value) in the 'tree view', and the result box jumps to its definition so you can see how it was defined, and eventually copy part of the code to re-use it in the input field.

Errors in the input field are hilighted when you execute a phrase (do not forget the ';;' at the end of your phrases).

You can use the File/Load file..., File/Save and File/Save as ... menus to load and save files. Note that the current file you're using is displayed in the title bar. It is the file your code will be saved into if you use the File/Save menu.

The File/Configuration menu opens the configuration window where you can change some colors, the font, and choose whether the values in the tree are automatically expanded or not (default is true, but it can take some time and memory for very large values).

9.4  Building a custom graphical toplevel

As for the ocaml toplevel, you have a command which lets you define your own graphical toplevel. This command is cam-mktop and is used the same way as the ocamlmktop command (see the OCaml manual for more information). The only differences are:

Chapter 10  OCamlmake-o-matic

10.1  Introduction

OCamlmake-o-matic (omom) is a set of two tools to easily generate Makefiles. Makefiles are generated from a omom file containing templates. Omom files can be edited through a graphical user interface.

Omom comes with a cameleon plugin for better integration and easier use.

10.2  Overview

An omom file contains templates. A template is a set of variables, i.e. identifiers with their corresponding values. Each template is associated to a file which contains a skeleton of the future Makefile. When generating the Makefile, all occurences of idenfitiers (more precisely of !(identifier)) in the chosen template will be remplaced by their values.

Omom files and templates can be edited with omom-edit this way:
$ omom-edit omom_file.cm
The tool to generate Makefile is omom-gen.
$ omom-gen omom_file.cm my_template > Makefile
where my_template is the name of the template contained in omom_file.cm you want to use.

There are at least two templates in each omom file: ocaml and common. Those two templates are special. They are not associated with a file (so they cannot be used as a a template name passed through the command line to omom-gen) and they cannot be edited as others templates. In a way, they are part of all other templates since the variables they contain are included in each template. The ocaml templates defines variables which are directly related to ocaml (such as OCAMLC and OCAMLOPT). You can modify the values of its variables but you can't add new variables. The common templates purpose is to share variables between templates. Some variable are predefined but you can add your own variables.

A variable can be activated or not. If it's not, the variable value will be set as its name as all other unknown identifiers.

The last thing to know about variables is that they can be of two types: string or list of strings. The type really matters because of the associated action. An action is a kind of filter which is applied to the value of a variable before the substitution in the skeleton file. An action can do different things depending on the type. At the moment, the only provided action is include which adds -I to each element of a list.

10.3  First step

First, we are going to edit a omom file:
$ omom-edit my_omom_file.cm



Figure 10.1: omom-edit



The window of figure 10.1 appears. Each tab of the window represents a template. You can inspect the two special templates.

To generate a Makefile, you must add at least another template. Click on the Templates/New template menu. Enter my_template as the template name and my_template.cmt as the associated file.

A new tab appears. Now, let's add a variable to our template. Select the new tab. Click on the Template/Add field menu. Choose VERSION as your variable name. Click on the check box to active the just created variable and enter 0.1 in the corresponding field as in figure 10.2



Figure 10.2: omom-edit



Now quit. When omom-edit ask you to save, answer yes.

We are now going to write our associated skeleton file:
$ cat > my_template.cmt
version:
        @echo VERSION: !(VERSION)
^D
where space before @echo is a tabulation.

Now, it's time to generate our makefile:
$ omom-gen my_omom_file.cm my_template
version:
        @echo VERSION: 0.1
$ omom-gen my_omom_file.cm my_template > Makefile
and to test it:
$ make version
VERSION: 0.1

10.4  First step with cameleon

You can use the omom plug-in in Cameleon, which gives access to the omom editor and the omom generator from within cameleon. See section 11.19.1 for more detail. Launch cameleon and select a CVS working directory. Add a file of type OCamlmake-o-matic spefication. The filename must end with .cm (it is the default pattern for omom files). Cameleon launches mom-edit. Two additionals templates are provided: configure.in and Makefile.in. Select configure.in. The field (AC_INIT must be initialized with the name of a .ml file of your project. Then select Makefile.in. EXE is the name of your binary. CMO_FILES is the name of your .cmo files and LIBS is the name of the libraries you use. Save and quit.

To generate your makefile, you must now launch the omom cameleon command. The easiest way is to click on List of internal commands in the Display menu and then double-click on omom.

First generate configure.in. Choose the configure.in template and enter configure.in as the target. Do the same for Makefile.in. Now generate the configure script, launching autoconf in your working directory.

Chapter 11  Cameleon

11.1  Introduction

The Cameleon tool is the glue between the other tools, to provide an integrated development environment. Files are managed with CVS, it includes various editors and a documentation browser. Plug-ins can be loaded to add functionalities.

11.2  Start

11.2.1  Launch command

The following command launches Cameleon :
cameleon [options] [dir1] ... [dirn]
You can use cameleon.opt instead of cameleon if the native code vers ion is available on your system, but then you won't be able to use plug-ins. The dir1 ...dirn arguments are a list of directories, each one being called a root directory, usually the root directory of one of your project. If you don't specify any directory, the current working directory becomes the only root directory. Note that you must use CVS[1] for the configuration management of your files in order to be able to use Cameleon.

The available options are:
-v
Display the version number and exit.
-norep
Use this option when the CVS repository is not available (for example when you are not connected to the network). You can then access your files through Cameleon but you cannot perfom any CVS action on it.
-com <command>
Make Cameleon execute the given <command> at launch time. Commands are described in section 11.4. This option can be used several times to perform several commands, in the order they appear on the command line.
-expand_dirs_at_start <true|false>
Indicate whether the directory trees in the tree view of the main window must be expanded at start or not. The default value is the one in your $HOME/.cameleon/gui configuration file (see section 11.5).
-check_edited_files_delay nb
When you edit files from Cameleon using Efuns or Xemacs, Cameleon check whether these files are still being edited, every nb miliseconds. You can change the delay here. The default value is the one in your $HOME/.cameleon/gui configuration file (see section 11.5).

11.3  Main window

The main window of Cameleon is shown on figure 11.1. The left part of this window shows directory trees, starting from the root directories. The right part of the window displays the list of files handled by CVS in the selected directory. The toolbar below the menu can be configured.



Figure 11.1: Cameleon main window.



11.4  Commands

Cameleon's functionalities are accessed through internal commands. We will write a command in red bold font. Since menus are totally customizable, we will refer to commands rather than menu entries to indicate the command used to perform an action.

In addition to Cameleon internal commands, external commands can be used. These commands are shell commands.

An internal command is a string, used as identificator to get the associated callback. This string must not begin with the character # and must not containt blanks, simple-quotes or double-quotes.

An external command is a string beginning with the character #. The command which gets executed is the string after the first #. In these commands, you can use some expressions to refer to the current state of Cameleon : All file and directory names are “quoted”, with the Filename.quote function of the OCaml standard library.

Commands can be launched through menu entries, buttons in the toolbar, or keyboard shortcuts.

Some internal commands are defined in Cameleon but more commands can be made available by loading plug-ins (see 11.16).

At last, internal commands can take parameters, the same way as shell commands in a shell, i.e. the arguments are separated by blanks and quotes can be used when an argument contains one or more blanks.

11.5  Configuration

The configuration of Cameleon is performed through the config command which opens the configuration window.

11.5.1  File types

A file type is defined by: The file types can be defined in the “File types” tab of the configuration window, as shown in figure 11.2.



Figure 11.2: Edition of file types.



When looking for the type of a file according to its name, Cameleon tries each regular expression in the order they appear in the list, and stops with the first regular expression matching the filename.
Note : The given regular expressions are used to match against the complete name of a file, starting from the root node name.

11.5.2  Documentation

The available documentation is defined as a list of doc-files (see 11.11). This list can be edited in the “Documentation files” tab of the configuration window.

11.5.3  Toolbar

You can customize the toolbar in the main window (see 11.3), by adding your own buttons, associated to the commands of your choice (internal or external, see 11.4). This is done through the “Custom toolbar” tab of the configuration window.

Each button of the toolbar is defined by : Note: Associating an internal command which is not available to a button will disable the button.

11.5.4  Menus

Menus and menu entries can be configured, through the “Menus” tab of the configuration window, shown on figure 11.3.



Figure 11.3: Edition of menus.



You can create menus, menu commands and separators. Menu commands are defined by a label (which will appear in the menu) and a command (internal of external, see 11.4). Activating a menu command launches the associated internal of external command.

Note: Associating an internal command which is not available to a menu command will disable the menu command.

While editing menus, you will have to mark one of them as the Doc menu, used to dynamically add entries, depending on the available doc-files (see 11.11).

11.5.5  Colors and fonts

The “Colors and fonts” tab lets you choose the colors and fonts used in the documentation browser (see section 11.10), the modules view (see section 11.9.2) and the background command execution window.

11.5.6  Keyboard shortcuts

The keyboard shortcuts can be configured to bind a key combination to a command (internal or external, see 11.4). You can also set the key bindings of the documentation browser (see 11.10).

The edition of key bindings is done in the “Key bindings” tab of the configuration window.

11.5.7  Plug-ins

With the bytecode executable cameleon, you can load plug-ins, to define new commands, new editors, new views, ...

The selected plug-ins are loaded at launch time.

There are two lists of available plug-ins: the shared plug-ins (in the shared plug-ins directory, see 11.15) and the personal plug-ins, in your $HOME/.cameleon/plugins directory.

In the “Plug-ins” tab of the configuration window you can select which plug-ins you want to load, among the list of available plug-ins.

The selected plug-ins are then loaded when you close the configuration window with the “Ok” button. Plug-ins already loaded are not loaded again.

11.5.8  Custom configuration tabs

The configuration window may contain other tabs. Indeed, a plug-in can add a configuration tab when it offers some configuration possibilities. See 11.16 for details.

11.6  CVS management

CVS actions can be performed from the main window with the following internal commands : add_dir, update_dir, commit_dir, tag_dir, add_file, add_binary_file, commit_files, tag_files, tags_of_file, remove_files, last_diff, diff_with, diff_between, resolve_conflicts.

The contextual menu which appears when you click with the third mouse button on a file of the files view (see section 11.9) or a directory gives access to these commands, as does the default CVS menu.

Note: You can use the $HOME/.ocamlcvsrc file to configure the CVS commands used in background (see chapter 7).

11.7  Editors

Editing a file is made with the edit command, or with the contextual menu which appears when you click with the third mouse button on a file. A file can be edited by various editors. The used editor depends on the type of each file. See 11.5.1 about associating an editor to a file type.
Currently, six editors are supported by Cameleon : Efuns[2], Emacs[3], XEmacs[5], DBForge, Report, Zoggy. A custom editor can also be associated to each file type to use another editor.

11.7.1  Efuns

In order to use Efuns as editor, efuns must be running as a server on the same machine. Cameleon communicates with the efuns process through sockets. When a file is edited, Cameleon asks to the efuns process to open this file. Cameleon can also ask Efuns if a file is saved, for example when a file is about to be commited. If the file is not saved, the user is asked whether he wants to save the file before committing or not.

11.7.2  Emacs and XEmacs

Emacs (respectively XEmacs) can be used as editor if an emacs (resp. xemacs) ser ver is running on the same machine. Cameleon communicates with Emacs (resp. XEmacs) through the emacsclient (resp. gnuclient) command. Cameleon can only ask to Emacs to open a file, so the user must take care himself about saving files before commiting, etc ... On the other hand, Cameleon can ask XEmacs if a file is being edited, if a file changed, ...

11.7.3  DBForge

The DBForge editor can be used to edit DBForge schema descriptions. See chapter 5 for details about these files. When a schema file is edited with DBForge, a window appears with the same graphical interface as the stand-alone DBForge tool. Closing this window closes the file. When using the DBForge editor, Cameleon can ask the user to save the edited file before committing, the same way as with Efuns.

11.7.4  Report

The Report editor can be used to edit Report XML document descriptions. See chapter 3 for details. The Report editor in Cameleon works the same way as the DBforge editor (see above).

11.7.5  Zoggy

The Zoggy editor can be used to edit Zoggy graphical interface descriptions. See chapter 4 for details. The Zoggy editor in Cameleon works the same way as the DBforge editor (see above).

11.7.6  Custom editors

If none of the predefined editors fit the user's needs, a custom editor can be defined and associated to a file type. Custom editors are defined by plug-ins (see 11.16). This is the case for the Omom editor (see chapter 10).

11.8  The directory tree

The directory tree shows the directories handled by CVS. You can perform CVS actions on the selected directory using the right commands (see section 11.6).

To choose whether the trees are expanded at start or not, you can use the expand_dirs_at_start command line option (see section 11.2.1).

11.9  The views

The right pane of the main window contains a notebook with different views of the selected directory. Two views are defined by default but more views can be added by plug-ins (see section 11.16).

11.9.1  The files view

The files view shows the files handled by CVS, in the selected directory. In this view you can perform CVS actions like commit, add file, ... The files are displayed according to their associated file type (see section 11.5.1).

11.9.2  The modules view

The modules view show the OCaml modules in the selected directory. To do so, it looks for a file dump.odoc in the selected directory. This file must be an OCamldoc dump file. It should contain information on the modules in the selected directory but you can put information on the modules you want in that file.

If the file does not exist, Cameleon try a make dump.odoc to create the file. If it does not work, and there is not dump.odoc file available, nothing is displayed.

When information is found, you can see the modules and classes trees on the left of the view, and selecting a module, module type, class or class type shows its elements on the right of the view. You can click with the right button of an element in the tree or the list to create a menu letting you edit the corresponding file at the line corresponding to the element definition. You can choose to open the implementation or the inferface file, depending of whether the documentation was created from the implementation file or the interface file, or both.

You can change the colors in this view in the configuration window (see section 11.5.5).

The “Refresh” button launch the make dump.odoc command and read the dump.odoc file to update the view.

11.10  The documentation browser

The documentation which can be accessed from Cameleon consist in information on OCaml modules. The user can choose these modules. Let's see how to choose these modules and browse their documentation.

11.11  Available documentation

The available documentation is defined by the user (see 11.5.2) as a list of doc-files. A doc-file contains information on toplevel modules, and must have been produced by the -dump option of ocamldoc (see [4]).

Each specified doc-file is loaded when Cameleon is launched. If the doc-file does not exist, a warning message points this out. All toplevel modules in the doc-files are sorted and the Doc menu is built from these modules (see 11.5.4).

In order to avoid too big menus, menus are cascaded. When a module is chosen in the Doc menu, its documentation is displayed in a documentation browser, described in 11.10.

At last, a label and an action can be associated to each doc-file (see 11.5.2). For each of these pairs of label and action, an entry is added to the Doc menu, with the given label. When the menu entry is activated, the given action is triggered. This action usually updates the corresponding doc-file. When the action is over, the Doc menu is updated according to the doc-file modifications.

11.12  Accessing the documentation

You can access the documentation on a module by selecting it in the Doc menu. It opens the documentation browser on this module.

The Doc menu also contains two entries, Exact search and Regexp search which allow the user to search for elements (as defined in [4]) by name, with the exact name or a regular expression. The search is performed on complete names, so you will find the iter function of the List module by using, for example, the Exact search command with the “List.iter” string.

If only one element matched the search, the documentation browser is open on this element, else a window appears showing all the results, and selecting one opens the documentation browser on this element.

The display_modules_box command can be used to show the list of available toplevel modules (it is created at launch time, but you can close it). In this window, called the doc modules box, you can double-click on a module to browse its documentation. You can walk through the list with the up and down arrows or use the 'A' .. 'Z' keys to go directly to the modules beginning with the letter corresponding to the key you hit. The “Return” key opens the selected module.

You can also use the top field to enter a string and perform an exact search on this string with the button below.

This field is a combo box, where you can add predefined strings. These predefined strings are bookmarks: you select a bookmark and then click the “Exact Search” button to go to the element (or the list of elements mathcing the search). To add a bookmark, use the add_bookmark command in the documentation browser.

11.13  Browsing the documentation

The documentation browser is a window showing the interface of a module or a class, with the comments of the source. It uses the information read from OCamldoc dump files.

You can click on some text to follow the link, for example you can click on a type name to go to its definition if it is available, like in a HTML document.

The following actions can be performed in the browser window:
next_element
Go to the next element or link in the window, from the current position.
previous_element
Go to the previous element or link in the window, from the current position.
follow_link
Follow the link on which we are.
follow_link_in_new
Open a new browser window to follow the link on which we are.
close
Close the browser window.
search
Search for a string in the window. You type the string in the field at the bottom of the window. Can be called several times to go to the next elements matchting the searched string.
back_search
Same as search but search backward instead of forward.
back
Go back to the previous page (like in a web browser).
add_bookmark
Add the element which was used to open the current page to the list of predefined strings in the search field of the doc modules box.
home
Go to the beginning of the page.
end
Go to the end of the page.
menu
Pop up a contextual menu.
These action are bound to keys, and you can edit these bindings in the configuration window (see section 11.5.6).

The contextual menu, which appears with the menu command or a click with the right button on an element, allow you to browse the follow a link in a new window, or open the file from which the documentation was created, by using the associated editor. The file is open as the right line where the element is defined.

Colors and fonts of the browser can be changed in the configuration window (see section 11.5.5).

11.14  The standalone browser

The docbrowser command (or docbrowser.opt if the native code version is installed) is a standalone documentation browser that you can launch without using Cameleon. It takes as arguments the OCamldoc dump files you want to browse. The colors, fonts and shortcuts are the ones defined in Cameleon (same configuration file).

11.15  The cam-config utility

The cam-config utility can be (and must be) used to get information on the installation of Cameleon, in the Makefiles of your own Cameleon plug-ins or your tools using the Cameleon tools and libraries.

It supports the following options:
-l
Print the directory of the Cameleon libraries.
-b
Print the directory of the Cameleon executables.
-m
Print the directory of the Cameleon man pages.
-t
Print the directory of the Cameleon templates.
-p
Print the directory of the Cameleon plugins.
-q
Print the directory of the Cameleon pixmaps.
-v
Print the version of Cameleon.

11.16  Plug-ins

Cameleon (bytecode version) can load plug-ins in the form of OCaml object-files (.cmo or .cma files).

Plug-ins can add: Some default plug-ins are available and are detailed below. To develop new plug-ins, you must use the Cam_plug module of Cameleon, as explained in subsection 11.21.

11.16.1  Shared/Personal plug-ins

There are two kinds of plug-ins: shared and personal. Shared plug-ins are available for everyone and are installed in the Cameleon shared plug-ins directory. This directory is printed by the following command:
cam-config -p
Personal plug-ins are in the user's $HOME/.cameleon/plugins directory.

Here are the default installed shared plug-ins. Do not forget that you can choose which plug-ins you want to use (see section 11.5.7).

11.16.2  The utils plug-in

This is a simple plug-in defining commands.

Commands

CommandDescription
execMake the user give a Cameleon command name and execute it. This comment is associated to the following command, thanks to our custom ocamldoc generator.
mozillaMake the user give an url and launch mozilla with this url. If no url is given, make the user type it. In this case, the default url begins with http:// or file:///, depending on whether a directory is selected or not.

11.16.3  The editors plug-in

This plug-in define additionnal editors for some file types.

Editors

EditorDescription
epeireLaunch epeire (the one installed with Cameleon) on the given Epeire configuration file.
gimpLaunch gimp on the given file.
gladeLaunch glade on the given file.
gvLaunch gv on the given file.
gvimLaunch a gvim serveur named "CAMELEON_GVIM" or connect to the existing one, if any.
xfigLaunch xfig on the given file.

11.16.4  The make plug-in

This plug-in defines the make internal command which launches the make utility on the given arguments, in the selected directory.

Commands

CommandDescription
makeRun make in the selected directory, on the given targets.

11.16.5  The omom plug-in

This plug-in adds an editor to edit OCamlmake-o-matic files.

Commands

CommandDescription
omomomom template target uses the selected OCamlmake-o-matic file to generate the given template in the given target file. omom does the same after having asked the template and the target file to the user.

Editors

EditorDescription
omomEdit OCamlmake-o-matic files in the graphical editor.

11.17  Developing your own plug-ins

To develop a Cameleon plug-in, you will have to use the Cam_Plug module, installed with Cameleon. This module defines functions to add editors, embedded applications, internal commands. Some functions are used to retrieve information on Cameleon current state (selected files, ...), and some utilities functions are also provided.

11.17.1  The Cam_plug module

Here is the interface of the Cam_plug module.

11.17.2  Example

Here is the code of a simple plug-in:

(*                                                                        *)
(*      This program is distributed in the hope that it will be useful,   *)
(*      but WITHOUT ANY WARRANTY; without even the implied warranty of    *)
(*      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the     *)
(*      GNU General Public License for more details.                      *)
(*                                                                        *)
(*      You should have received a copy of the GNU General Public License  *)
(*      along with this program; if not, write to the Free Software       *)
(*      Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA          *)
(*      02111-1307  USA                                                   *)
(*                                                                        *)
(*      Contact: Maxence.Guesdon@inria.fr                                *)
(**************************************************************************)


(** Utils plugin. This plugin provides some basic commands to show how to create your own plugin.*)


open Cam_plug

(** Make the user give a Cameleon command name and execute it. This comment is associated to the following command, thanks to our custom ocamldoc generator. @command exec *)

let exec args =
  match args with
  | [] ->
      (
       let coms = Cam_plug.available_commands () in
       let com = ref (try List.hd coms with _ -> ""in
       let p = Configwin.combo
           ~f: (fun s -> com := s)
           ~new_allowed: true
           ~blank_allowed: false
           "Command : "
           coms
           !com
       in
       match Configwin.simple_get "execute" [p] with
         Configwin.Return_cancel | Configwin.Return_apply -> ()
       | Configwin.Return_ok -> Cam_plug.eval !com ()
      )
  | l ->
      let com = String.concat " " l in
      Cam_plug.eval com ()


(** Make the user give an url and launch mozilla with this url. If no url is given, make the user type it. In this case, the default url begins with http:// or file:///, depending on whether a directory is selected or not. @command mozilla *)

let mozilla args =
  let url_opt = 
    match args with
      url :: _ -> Some url
    | [] ->
        GToolbox.input_string ~title: "mozilla" 
          ~text: (match selected_dir() with None -> "http://" | Some s -> "file:///"^s) 
          "url: " 
  in
  match url_opt with
    None -> ()
  | Some s -> ignore (Sys.command ("mozilla "^(Filename.quote s)^" &"))

let _ = add_command "exec" "execute a prompted command" exec 
let _ = add_command "mozilla" "launch mozilla on a given url" mozilla

You can compile it with the following command:
ocamlc -c -I +cameleon plugin.ml
Then place the resulting .cmo file in the shared plug-ins directory or your personal plug-ins directory. Cameleon will let you choose this new plug-in to load, in the “Plug-ins” tab of the configuration window (see section 11.5.7). If you develop such plug-ins and want to distribute them, please e-mail maxence.guesdon@inria.fr, so your plug-ins can be referenced on a Cameleon plug-ins page.

Chapter 12  Other libraries

12.1  Introduction

Cameleon offers other libraries which can be of great help to develop applications. They are described below.

12.2  Options

This library is used to manage the configuration file(s) of an application. You simply define your options and it performs the loading and saving of the options. Each option is defined from an option class (for example string_option) or from a combination of classes (for example list_option string_option).

Values of options are read and written with the two operators !! and =:=.

The format of the configuration file looks like OCaml code, and is human readable.

The library interface is described below, then you can find a commented example.

12.2.1  The Options library

Here is the interface of the Options library.

12.2.2  Example

This example is inspired from the make plug-in of Cameleon.
open Options

(* We create an option file *)
let op_file = create_options_file "my_option_file"

(* We define a new option, named "targets" in the configuration file.
   The name is a list of strings, to allows nested groups of options
   in the configuration file. Try to give an option name with more 
   than one string, and you will see that the option appears as 
   a record field in the configuration file.*)
let op_targets = define_option op_file ["targets"]
    "some help text" (* this help text will be saved in the configuration file
                        if you use the save_with_help function *)
    (list_option string_option) (* our option is a list of strings *)
    ["all" ; "byte" ; "clean" ; "depend" ; "doc" ; "opt" ; "%s"]
                                (* and the list above is its default value *)

(* We load the file, reading the values of the defined options. *)
let _ = load op_file

(* We save the file, with the help text as comments in the file. *)
let _ = save_with_help op_file

(* We can read the op_targets value with the !! operator *)
let l = !!op_targets

(* We can set the value of op_targets with the =:= operator *)
let _ = op_targets =:= [ "my" ; "new" ; "liste"]

12.3  Okey

This library contains some convenient functions to add handlers of key press events in LablGtk applications.

12.3.1  The Okey library

Here is the interface of the Okey library.

12.4  Configwin

This library offers convenient functions to make the user edit values (lists, strings, booleans, colors, fonts,...) in LablGtk applications. Here is the library interface, followed by an example.

12.4.1  The Configwin library

Here is the interface of the Configwin library.

12.4.2  Example

let _ = GMain.Main.init ()

open Configwin

let param1 = string ~help: "a string" "a string" "a value" 
let param2 = bool ~help: "bool value" "a boolean" true
let param3 = filename ~help: "a file name" "a file name" "foo" 
let param4 = strings 
    ~help: "a list of strings"
    ~eq: (fun _ -> fun _ -> false)
    ~add: (fun () -> ["another string" ; "and another string"])
    "a string list" 
    ["foo" ; "bar"] 
let param5 = color ~help: "a color" "a color" "Red" 
let param6 = font ~help: "a font" "a font" "7x13bold" 
let param7 = date ~help: "a date" "a date" (1, 0, 2002)
let n = ref 0
let param8 = list 
    ~help: "a list of int"
    ~add: (fun () -> incr n; [!n])
    ~titles: ["n" ; "n * n"]
    "an int list" (fun n -> [string_of_int n ; string_of_int (n*n)])
    [1 ; 2 ; 3]
let param9 = filenames ~help: "a list of filenames" "filenames" []
    
let structure = Section_list 
  ("Section 1", 
   [
    Section ("Section 1.1",
             [ param1 ; param2 ; param5 ; param6 ; param7 ; param9]);
    Section ("Section 1.2",
             [ param3 ; param4 ; param8])
   ] 
  )

let _ = Configwin.edit "Titre" [structure]
Figure 12.1 shows the window displayed.



Figure 12.1: Configwin example.



12.5  IoXML

This library is included in Cameleon thanks to its author Daniel de Rauglaudre. The following text comes from the README file of the IoXML distribution.

IoXML is a Camlp4 syntax extension for OCaml mli and ml files which generates XML parsers and printers for all types you define.

12.5.1  Usage

If we have two files "foo.mli" and "foo.ml":

Compilation:
ocamlc -pp "camlp4o pa_ioXML.cmo" -I +camlp4 -c foo.mli
ocamlc -pp "camlp4o pa_ioXML.cmo" -I +camlp4 -c foo.ml


Pretty print (for info):
camlp4o pa_ioXML.cmo pr_o.cmo foo.mli
camlp4o pa_ioXML.cmo pr_o.cmo foo.ml


Linking:
ocamlc -I +camlp4 ioXML.cmo ...files...

12.5.2  Details

The generated functions are, for each type "bar": The function xparse_bar takes a XML tree as parameter, defined in IoXML.ast. To get it from a file (or any stream), the library function IoXML.parse_xml_list reads XML input. Another function IoXML.parse_xml reads just one XML item.

If the type has parameters, the parser and printer functions receive as first parameters, the parser and printers for them.

The function xprint_bar takes a Format.formatter function as parameter.

12.5.3  Example

For example if the type bar is defined as:
    type ('a, 'b) bar =
      Leaf of 'a
    | Node of 'b * ('a, 'b) bar * ('a, 'b) bar
The generated functions are of types:
    xparse_bar:
       (IoXML.ast -> 'a) -> (IoXML.ast -> 'b) -> IoXML.ast -> ('a, 'b) bar   
    xprint_bar:
       (Format.formatter -> 'a -> unit) ->
       (Format.formatter -> 'b -> unit) ->
            Format.formatter -> ('a, 'b) bar -> unit
If we have e.g. values of type (int, string) bar, a typical parsing usage is:
      let ic = open_in file_name in
      let strm = Stream.of_channel ic in
      let v =
         xparse_bar IoXML.xparse_int IoXML.xparse_string
            (IoXML.parse_xml strm)
      in ...
and a typical printing usage is (see standard module Format):
      let ppf = Format.std_formatter in
      IoXML.xprint ppf "@[%a@]@."
        (xprint_bar IoXML.xprint_int IoXML.xprint_string) v;

12.6  Gpattern

This library offers convenient classes to use some LablGtk widgets. by now it only has one class, allowing to quickly build a clist with some events already bound and handling the selection of elements.

12.6.1  The Gpattern library

Here is the interface of the Gpattern library.

Appendix A  Index of default internal commands

Commands

CommandDescription
about_boxDisplay the "about..." box.
add_binary_file.Prompt for a binary file name to add in the selected directory. Then perform the cvs add command.
add_dirPrompt to add a directory to the selected one. Then perform the cvs add command.
add_file.Prompt for a file name to add in the selected directory. Then perform the cvs add command.
commit_dircvs commit the selected directory.
commit_filesPrompt for a comment, then perform a cvs commit on the selected files.
configOpen the configuration window.
diff_betweenShow the differences between two versions of the first selected file. The user is promped to select the two versions to compare.
diff_withAsk for a version of the first selected file, and show differences between the current version and the selected version.
display_modules_boxDisplay or update the box with the list of top modules whose documentation is available.
editEdit the selected files with their associated editor(s).
edit_withEdit the selected files with an editor chossen among the vailable ones.
last_diffShow the differences between the first selected file and its original version in the repository.
list_commandsDisplay the list of available internal commands, with their description.
quitQuit Cameleon.
reload_pluginMake the user select a loaded plug-in and reload it.
remove_filesAsk for confirmation then performs a cvs remove on the selected files.
resolve_conflictsLaunch the conflict resolving assistant on the first selected file.
tag_dirPrompt for a tag and tag all files under the selected directory. Before, it checks whether one or more files already have the given tag, and ask for confirmation if is the case.
tag_filesPrompt for a tag and tag the selected files. Before, it checks whether one or more files already have the given tag, and ask for confirmation if is the case.
tags_of_fileShow the list of tags of the first selected file.
update_dircvs update the selected directory.
update_dir_viewUpdate the directory view.


Appendix B  Index of plug-ins

Plug-ins

Plug-ins



Utils
Editors
Make
Omom_plugin

References

[1]
CVS Reference Manual. http://www.cvshome.org/docs/manual/cvs.html.

[2]
Efuns, an emacs clone in OCaml. http://pauillac.inria.fr/~lefessan.

[3]
Emacs user's manual. http://www.emacs.org.

[4]
OCamldoc documentation and user's manual. http://caml.inria.fr/ocaml/htmlman/manual029.html.

[5]
XEmacs user's manual. http://www.xemacs.org.

This document was translated from LATEX by HEVEA.