(**************************************************************************)
(*                   Cameleon                                             *)
(*                                                                        *)
(*      Copyright (C) 2002 Institut National de Recherche en Informatique et   *)
(*      en Automatique. All rights reserved.                              *)
(*                                                                        *)
(*      This program is free software; you can redistribute it and/or modify  *)
(*      it under the terms of the GNU General Public License as published by  *)
(*      the Free Software Foundation; either version 2 of the License, or  *)
(*      any later version.                                                *)
(*                                                                        *)
(*      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                                *)
(**************************************************************************)

(** Interface for plug-ins *)

type command = string

(** The directory with config files. Can be used by a plug-in
   to create its own config file. *)
val rc_dir : string

(** Display the given string in the label at the bottom of the main window. *)
val display_message : string -> unit 

(** The class type of embedded applications. *)
class type embedded_app =
  object
    (** The box, to pack it in something. *)
    method box : GPack.box

    (** The method to call to close the app.*)
    method close : unit

    (** To perform some initializations with a window. *)
    method init_window : GWindow.window -> unit
  end

(** [add_embedded_app com f] registers an application which can be started
   by command [com]. When this command is triggered, [f ()] is evaluated to
   get an application object. *)
val add_embedded_app : command -> (unit -> embedded_app) -> unit

(** [add_command com desc f] adds the command [com] to the list of
   registered commands, with description [desc] and callback [f].
   The callback takes a list of arguments in parameter.
   If the same command exists in the table, it is hidden by the new one.
*)
val add_command : command -> string -> (string list -> unit) -> unit

(** Return the list of the available commands. *)
val available_commands : unit -> command list

(** [add_config_box f] registers a function creating a section for
   the configuration window. This function is called each time
   the configuration window is created. *)
val add_config_box : (unit -> Configwin.configuration_structure) -> unit

(** Access to the  selected directory (its name as it appears in the tree, absolute or relative). *)
val selected_dir : unit -> string option

type cvs_status = 
  | Up_to_date (** The file is identical with the latest revision in the 
                  repository for the branch in use. *)
  | Locally_modified (** You have edited the file, and not yet committed
                        your changes. *)
  | Locally_added (** You have added the file with add, and not yet
                     committed your changes. *)
  | Locally_removed (** You have removed the file with remove, and not
                       yet committed your changes. *)
  | Needs_checkout (** Someone else has committed a newer revision to the
                      repository. The name is slightly misleading; 
                      you will ordinarily use update rather than checkout
                      to get that newer revision. *)
  | Needs_Patch (** Like Needs Checkout, but the CVS server will send a
                   patch rather than the entire file. 
                   Sending a patch or sending an entire file accomplishes
                   the same thing. *)
  | Needs_Merge (** Someone else has committed a newer revision to the 
                   repository, and you have also made modifications to the 
                   file. *)
  | Conflicts_on_merge 
                (** This is like Locally Modified, except that a previous
                   update command gave a conflict. If you have not already
                   done so, you need to resolve the conflict. *)
  | Unknown (** CVS doesn't know anything about this file. For example, 
                   you have created a new file and have not run add. *)

type editor = 
    Efuns
  | Dbforge
  | Emacs
  | XEmacs
  | Report
  | Zoggy
  | Custom_editor of string

type file_type = {
    mutable ft_regexp_string : string ;
    mutable ft_regexp : Str.regexp ;
    mutable ft_name : string ;
    mutable ft_color : string option;
    mutable ft_edit : editor ;
    mutable ft_templates : string list ;
    mutable ft_binary : bool
  } 

type file =
    {
      f_name : string ; (** relative or absolute file name *)
      f_abs_name : string ; (** absolute file name *)
      f_date : float ; (** date of last update of the structure *)
      f_date_string : string ; (** cvs date string *)
      f_work_rev : string ; (** cvs working revision *)
      f_rep_rev : string ; (** cvs repository revision *)
      f_status : cvs_status ; (** cvs status *)
      mutable f_type : file_type ; (** type of file *)
    } 

(** Access to the  selected files. *)
val selected_files : unit -> file list

(** {2 Command execution} *)

(** [eval com ()] execute the given command.
   The command is a string and can be an internal command (with or without
   arguments) or a shell command (beginning with '#').
   Catch all the exceptions raised by the function. Do nothing if
   there is no function associated to the command.*)
val eval : string -> unit -> unit

(** [background_execute com ()] execute the given shell command in background,
   showing in a window the output (stdout and stderr) of the command.
   Catch all the exceptions raised by the function. 
   @param width the width of the window
   @param height the height of the window
*)
val background_execute : ?width: int -> ?height: int -> command -> unit -> unit

(** Same as [background_execute] but performs substitution
   of %tags in the given command.*)
val background_execute_with_subst : ?width: int -> ?height: int -> command -> unit -> unit

(** {2 Custom editors} *)

(** The class type to represent an editor. *)
class type editor_app = 
  object
    method close : unit
    method reload : unit
    method save : unit
    method changed : bool
  end

(** [add_editor id f] adds an editor identified by [id],
   and [f] is the function used to create an optional instance
   of that editor, for the given file. [id] is the string
   which must be used in the editor field of a file type.
   Default editor commands cannot be overriden.
   If the given function returns None as editor, Cameleon
   does not mark the file as open. If the function returns
   (Some editor), Cameleon can ask this editor to close
   (when the user quits Cameleon), to reload, or to save
   if the changed method returns [true] (before a commit for example).
*)
val add_editor : string -> (?char:int -> file -> editor_app option) -> unit

(** This function must be called when an editor is closed,
   to warn Cameleon that this file is closed. If the function given
   to add_editor returned None (i.e. no editor created), you don't have
   to call this function, since Cameleon did not mark the file as
   open.
   Cameleon will not allow to edit the file as long as it is marked as open.
*)
val close_file : file -> unit

(** {2 Option management} *)

(**
 This module implements a simple mechanism to handle program options files.
  An options file is defined as a set of [variable = value] lines,
  where value can be a simple string, a list of values (between brackets
or parentheses) or a set of [variable = value] lines between braces.
The option file is automatically loaded and saved, and options are
manipulated inside the program as easily as references. 

   Code from Fabrice Le Fessant.
*)
module Options :
    sig
      type 'a option_class
        (** The abstract type for a class of options. A class is a set of options
	   which use the same conversion functions from loading and saving.*)
	    
      type 'a option_record
        (** The abstract type for an option *)

      type options_file

      val create_options_file : string -> options_file
      val set_options_file : options_file -> string -> unit
      val prune_file : options_file -> unit  

      (** {3 Operations on option files} *)
  
      val load : options_file -> unit
        (** [load file] loads the option file. All options whose value is specified
	   in the option file are updated. *)
  
      val append : options_file -> string -> unit
        (** [append filename] loads the specified option file. All options whose 
	   value is specified in this file are updated. *)
  
      val save : options_file -> unit
        (** [save file] saves all the options values to the option file. *)

      val save_with_help : options_file -> unit
        (** [save_with_help ()] saves all the options values to the option file,
	   with the help provided for each option. *)
  
      (** {3  Creating options} *)  
      val define_option : options_file ->
	string list ->  string -> 'a option_class -> 'a -> 'a option_record
      val option_hook : 'a option_record -> (unit -> unit) -> unit
    
      val string_option : string option_class
      val color_option : string option_class
      val font_option : string option_class
      val int_option : int option_class
      val bool_option : bool option_class
      val float_option : float option_class
      val string2_option : (string * string) option_class
  
      (** {4 Parameterized options} *)

      val list_option : 'a option_class -> 'a list option_class
      val smalllist_option : 'a option_class -> 'a list option_class
      val sum_option : (string * 'a) list -> 'a option_class
      val tuple2_option :  
	  'a option_class * 'b option_class -> ('a * 'b) option_class
      val tuple3_option : 'a option_class * 'b option_class * 'c option_class ->
	('a * 'b * 'c) option_class

      (** {3  Using options} *)
  
      val ( !! ) : 'a option_record -> 'a
      val ( =:= ) : 'a option_record -> 'a -> unit

      val shortname : 'a option_record -> string
      val get_help : 'a option_record -> string  
  
      (** {3 Creating new option classes} *)

      val get_class : 'a option_record -> 'a option_class
	  
      val class_hook : 'a option_class -> ('a option_record -> unit) -> unit
	  
      type option_value =
	  Module of option_module
	| StringValue of  string
	| IntValue of int
	| FloatValue of float
	| List of option_value list
	| SmallList of option_value list
	      
      and option_module =
	  (string * option_value) list
	    
      val define_option_class :
	  string -> (option_value -> 'a) -> ('a -> option_value) -> 'a option_class
	      
      val to_value : 'a option_class -> 'a -> option_value
      val from_value : 'a option_class -> option_value -> 'a
	  
      val value_to_string : option_value -> string
      val string_to_value : string -> option_value
      val value_to_int : option_value -> int
      val int_to_value : int -> option_value
      val bool_of_string : string -> bool
      val value_to_bool : option_value -> bool
      val bool_to_value : bool -> option_value
      val value_to_float : option_value -> float
      val float_to_value : float -> option_value
      val value_to_string2 : option_value -> string * string
      val string2_to_value : string * string -> option_value
      val value_to_list : (option_value -> 'a) -> option_value -> 'a list
      val list_to_value : ('a -> option_value) -> 'a list -> option_value
      val smalllist_to_value : ('a -> option_value) -> 'a list -> option_value
	  
      val set_simple_option : options_file -> string -> string -> unit
      val simple_options : options_file -> (string * string) list
      val get_simple_option : options_file -> string -> string
      val set_option_hook : options_file -> string -> (unit -> unit) -> unit
	  
      val set_string_wrappers : 'a option_record -> 
	('a -> string) -> (string -> 'a) -> unit
	    
      val simple_args : options_file -> (string * Arg.spec * string) list
    end

(** {2 Custom views} *)

(** You can define new views using this module. 
   A view is a box in the right part of the main window,
   updated when it is the active view and the user changes
   the selected directory.
*)
module View :
    sig
      class type view = 
	object
          (** Used to pack the view in the notebook widget. *)
	  method coerce : GObj.widget

	  (** Update the view according to the given optional selected directory. *)
	  method display_dir : string option -> unit
	end
	
      (** [add_view view label] adds the given [view] to the
	 notebook of views, with the given [label].*)
      val add_view : view -> string -> unit
    end
