Here are some questions and answers about Chamo and its usage.

Using OCaml code and commands in Chamo
Chamo is OCaml-scriptable. What does it mean ?

This means that you can fully customize Chamo with pieces of OCaml code, the same way you can customize Emacs with lisp code. There are multiple ways to do so. For example, you can place some code in your file ~/.config/chamo/chamo_init.ml. This file is evaluated when chamo.byte is launched. In this file, you can access any part of Chamo. Refer to the reference documentation for information about the API of the available modules.

For example, to display the "about box" at launch time, simply add to chamo_init.ml the following code:

Gui.show_about_dialog ();;

The same effect could be achieved by calling the command "about" with no arguments. To do so from OCaml code, you can use the function Chamo.Commands.eval_command:

Chamo.Commands.eval_command "about";;

Another way to evaluate OCaml code to add your own command or whatever you want is to call the eval command. When called without argument, this command prompts the user for OCaml code to evaluate. If an argument is given, it is evaluated as OCaml code. See here for details on commands. So, putting the following code in your file chamo_init.ml:

Chamo.Commands.eval_command "eval \"let x = 1;;\"";;
is the same as simply putting
let x = 1;;

Another way to perform some customization is to use the --use command line option to indicate a file containing OCaml code to evaluate at launch time.

From a technical point of view, the chamo.byte executable includes the compiler-libs.toplevel package, which offers functions to evaluate OCaml code. Then, some initializations are done by the module Eval to make the interpreter look for module interfaces in the directories of required packages detected during configuration. This is done by evaluating some #directory directives.

All the answer above is true for the bytecode version of Chamo (chamo.byte). It is false for the native code version (chamo).

What are commands ?

Commands are functions associated to a name. The name is a string. See here about how to define a command. The commands can take parameters, which are strings too. The call to a command is then a string of the form: command arg1 arg2 ..., like a shell command. Arguments are optional. Some commands require arguments, some don't. Some commands will prompt the user for missing arguments.

By default, the A-x (Alt-x) keys are bound to the prompt_command command which uses the minibuffer of the active window to make the user type in a command (name and arguments). Then the text entered is given to the command command which parses its first argument to separate the command name from arguments and really launches the command. Quoting of arguments works the same way as in the shell (with simple or double quotes).

How to define new commands ?

Commands are defined in OCaml using the functions in module Commands. They are composed of a name, a list of parameter names, an optional description for remaining parameters and the OCaml function which is called when the command is launched. This function is of type string array -> unit Lwt.t. The parameters of the command are passed in the string array. The indications about parameters names can be used by higher level functions to prompt the user for missing parameters, with the names of the parameters, so that the user knows what to enter.

Here is an example of the creation of a command which displays the message in the first argument, or "Alert!" if there is no argument: FIXME/UPDATEME:

let alert_message args =
  let message =
    if Array.length args < 1 then
      "Alert!"
    else
      Misc.to_utf8 args.(0)
   in
   GToolbox.message_box "Alert message" message;;
let com = Chamo.Commands.create_com
   "alert_message" [| "Message to display" |] alert_message;;
Chamo.Commands.register com;;

It is useful to name and make visible the function associated to the command, so that it is also directly available in OCaml code, rather than calling

Chamo.Commands.eval_command "alert_message my_message";;
or
Chamo.Commands.launch_command "alert_message" [|"my_message"|];;
Of course, calling directly the function which was first associated to the command alert_message will short-circuit any redefinition of the command.

It is also possible to complete existing commands, by adding some code to execute before or after the original code of a command. This is done with the functions Chamo.Commands.register_before and Chamo.Commands.register_after. For example, if we want alert messages to be logged, we could use something like

let log_message args =
  (* log the message(s) in the arguments *)
  ...
;;
Chamo.Commands.register_before
  (Chamo.Commands.create_com
     "alert_message" [|"Message to display"|] log_message);;

Which commands are available ?

The list of available command names can be obtained with Chamo.Commands.available_command_names (). Then it is easy to obtain, for each command, the names of its parameters:

let f name =
  let com = Chamo.Commands.get_com_or_fail name in
  print_string com.Chamo.Commands.com_name;
  Array.iter (fun s -> Printf.printf " (%s)" s) com.Chamo.Commands.com_args;
  (match com.Chamo.Commands.com_more_args with
     None -> ()
   | Some s -> Printf.printf " (%s...)" s
  );
  print_newline ()
;;
List.iter f (Chamo.Commands.available_command_names());;

A naming convention is needed to get some consistency in command names. By now, general commands are not prefixed. The commands relative to a sourceview mode (for example the "ocaml" mode of the "sourceview" view) should be prefixed by the mode name (e.g. ocaml_). The commands relative to a view (like "sourceview" or "odoc") should be prefixed by the view name (e.g. sourceview_ or odoc_). The convention is to separate words in command names by _ and not -.

Configuration files
Where are stored the configuration files of Chamo ?

The user's global configuration files of Chamo are stored in the ~/.config/chamo/ directory and are prefixed with chamo.. The files are created if they don't exist. They are human readable with a JSON syntax.

There are also "local" configuration files, that is files stored in the directory where Chamo was launched. By now, we can find:

  • .chamo.sourceview.buffers which contains the list of open buffers in the "sourceview" view, and the position of the cursor in each of them,
  • .chamo.layout.xml which describes the layout of all open windows. This file is created on demand by the store_layout command. When Chamo is launched and this file exists in the current directory, it is read and all windows and views are created accordingly, so that you keep all your views arranged like they were when you stored the layout.
  • .chamo_init.ml which is evaluated by chamo.byte at launch time, after the ~/.config/chamo/chamo_init.ml file of the user; it can be used to add some customization relative to a particular directory.
Wow ! There are a lot of Chamo configuration files in ~/.config/chamo/ !

Indeed. But don't panic, there's a logical organisation.

  • In chamo.core, you will find some values concerning internal details, like the default charset encoding used to read/write files and convert to/from UTF-8 (Stk uses UTF-8).
  • chamo.gui contains some options common to all Chamo windows, like key bindings.
  • chamo_init.ml is evaluated when chamo.byte is launched; it contains OCaml source code. Think of it as the ~/.emacs file of Emacs.
  • chamo.views defines some options about view management, in particular the associations between filename patterns and views, and the default view to use when opening a file.
  • chamo.odoc and chamo.sourceview contain respectively the options of the "odoc" and "sourceview" views. As you understand now, the standard name of the configuration file of a view is chamo.<view name>.
  • Each available mode of the "sourceview" view has its own configuration file named chamo.sourceview.mode.<mode name>, for example chamo.sourceview.mode.ocaml or chamo.sourceview.mode.changelog.
Views
What are views ?

Views in Chamo are different ways to edit or display files. The most commonly used view in the "sourceview" view, which allows the edition of any text file. It is based on Stk texview widget and can highlight syntax elements. Other views are available for some kinds of files:

  • FIXME/UPDATEME: the "odoc" view can be used to display and browse the contents of OCamldoc dump files, and files can be open directly at the location of an element from this view (by double-clicking or from the menu which pops-up when button 3 is pressed).

Views define also their own description of menus and key bindings. When a view has the input focus, the menus it describes are available in the menubar of the parent window of the view, and the key bindings it defines are handled, in addition to the key bindings common to all Chamo windows.

How do I choose which view is used to edit a file ?

Chamo has no way to guess the view you want to use to edit a file. You have to give some indications. This is done in the file ~/.config/chamo/chamo.views, in option view_from_filename_patterns, by giving pairs (regular expression, view name). The regular expressions are tried in the given order to match the name of the file to open. When a regular expression matches, Chamo uses the view with the associated name to open the file. A default view is used when none of the regular expressions match the file name. The default view name can be set with option default_view. The default value of default_view is "sourceview".

This file is read at launch time, so you must restart Chamo if you modified it, or evaluate the following OCaml code to reload the values of options:

View_rc.read();;

Values of options can also be set using OCaml code. Refer to the documentation of the Ocf library to manipulate the options. For example, to add a new association between a filename pattern and a view name, use the following OCaml code (here we add a pattern so that files with ".ocamldoc" extension are open with the "odoc" view):

let l = Ocf.get View_rc.filename_view_patterns in
Ocf.set View_rc.filename_view_patterns (("\\.*ocamldoc$", "odoc") :: l) ;;

It is also possible to store the values of options, this way:

View_rc.write ();;

Can you give me some details about the "sourceview" view ?

This view can be used to edit any text file. It is based on the Textview widget of the Stk library. As in Emacs, this view separates the buffers from the views on the screen. So a buffer can be displayed in various views, and some buffers can be present but not visible. There cannot be two different buffers on the same file. Since Stk buffers use UTF-8 strings, the contents of the edited files must be converted to UTF-8 when used in a buffer and converted back to the file encoding when the file is saved. The default encoding used is the one associated to the "LOCALE" environment variable, then if it fails, the default_charset option of the user's ~/.config/chamo/chamo.core file is used. If it still fails, the user is prompted to choose an encoding among the ones found on the system at configuration and compilation time.

Prompting the user to choose an encoding when the default ones fail is not yet implemented.

Common manipulations of text are allowed through commands and are bound to keys. Check your ~/.config/chamo/chamo.sourceview file for what commands are bound. Sourceview specific commands begin with sourceview_.

Syntax highlighting in a buffer is made by the Textview widget according to the language associated to the buffer. Check the language_mime_from_filename_patterns option of your file ~/.config/chamo/chamo.sourceview: these are the associations between filename patterns and mime types. Then, the mime type is used to retrieve the language specification defining syntax elements. FIXME/UPDATEME:Since Chamo uses the module Gtksv_utils, the styles of the elements of each language are shared with the other applications using this module. Styles of the "sourceview" views and syntax highlighting can be modified using the "Preferences" box accessible from the menu "File/Preferences". The syntax mode of the buffer in a view is displayed between square brackets below the view, next to the buffer name and the line and column numbers.

Chamo sourceview buffers can also have an associated mode. A mode is composed of a name, a description of the menus to display and the keyboard bindings to handle when the view of the buffer has the input focus. Associations between filename patterns and mode names are defined in option mode_from_filename_patterns of the user's file ~/.config/chamo/chamo.sourceview. This means that commands "specific to a mode" are available even on buffers with another mode associated; it is just a matter of key bindings and menus which give direct access to commands. Options of modes, like key bindings, are stored (by convention) in a configuration file specific to the mode. For example, the configuration options of the "ocaml" mode are stored in the user's file ~/.config/chamo/chamo.sourceview.mode.ocaml.

How do I define a new sourceview mode ?

This is done with some OCaml code. Modes are represented by objects of class type Sourceview.mode. Then, an instance of your mode class must be registered with Sourceview.register_mode. Then, add some association between a filename pattern and your mode name and it's ok. Have a look at the code of another mode, e.g. the ocaml mode.

What modes are availables ?

By now, there are not a lot of modes. Here is a list of the available modes, with the commands it provides through a key binding indicated between parenthesis:

  • "ocaml": ocaml_indent_line (Tab), ocaml_indent_buffer (C-x C-Tab), ocaml_switch_file (C-x C-a), ocaml_display_type_annot (A-t), ocaml_copy_type_annot (CA-t), ocaml_display_call_annot (A-c), ocaml_display_indent_annot (A-i), ocaml_jump_to_local_def (A-j), ocaml_show_stack_calls (CA-c), ocaml_expand_ext_idents (CA-x), ocaml_build (C-o C-c),
  • "makefile": sourceview_insert "\t"' (Tab),
  • "changelog": changelog_new_day_entry' (C-x a), sourceview_insert "\t"' (Tab).

Contributions (new modes or new commands) are very welcome !

Key bindings
How/where are key bindings defined ?
There are various sets of key bindings:
  • Chamo-wide key bindings, usable in all Chamo edition windows, whatever the active view is; these key bindings are defined in the file ~/.config/chamo/chamo.gui.
  • key bindings associated to a kind of view; these bindings are defined in the file ~/.config/chamo/chamo.V where V is the name of a view. So, the bindings of "sourceview" views are defined in the file ~/.config/chamo/chamo.sourceview. The bindings associated to a kind of view are active only when the active view is of this kind.
  • sourceview mode specific bindings; these are active only when a mode is selected in the active sourceview; they are defined in the file ~/.config/chamo/chamo.sourceview.mode.M where M is the name of the mode, such as ocaml.

All these files are created with default values if they don't exist when Chamo is launched.

The final set of active key bindings is the union of global key bindings and the ones of the active view (with eventually the ones of the active mode).

Where can I find a list of key specification to define my own bindings ?

The key identifiers usable in configuration files can be found here. You should be able to find the corresponding string; for example "page up" will be referenced with the identifier "PageUp".

How can I know the list of available commands I can associate a key binding to ?

Most of predefined commands are already bound to a key combination, so you can already have a look at the various configuration files for command names. If you don't find what you're looking for, you can execute the following command in a bytecode version of chamo:

eval "Chamo.Commands.available_command_names ()"

This command will evaluate the given ocaml expression, which returns the list of names of registered commands. The list is displayed in the ocaml evaluation output window.

Troubleshooting
When I open a file, some characters are badly displayed; it seems there is an encoding problem. How is the encoding of files handled ?

By default, Chamo considers that files are encoded as specified in file ~/.config/chamo/chamo.core (the default value when this file is created is ISO8859-1). When a file is open, Chamo converts the contents of the file from this encoding to UTF-8 to display it correctly in Stk windows. If you want to open a file which is in a different encoding, you can use the command open_file_with_encoding which will let you specify the encoding of the file to open. You can also change the default encoding used, by modifying the value in the file ~/.config/chamo/chamo.core.