(*********************************************************************************)
(*                Chamo                                                          *)
(*                                                                               *)
(*    Copyright (C) 2003-2021 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 Lesser General Public License version        *)
(*    3 as published by the Free Software Foundation.                            *)
(*                                                                               *)
(*    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                                          *)
(*                                                                               *)
(*********************************************************************************)

let factory_name = "sourceview"
let rc_file = Config.rc_file factory_name

let mode_rc_file mode_name =
  Config.rc_file (Printf.sprintf "%s.mode.%s" factory_name mode_name)
let local_mode_rc_file mode_name =
  Config.local_dir_rc_file (Printf.sprintf "%s.mode.%s" factory_name mode_name)

let bookmarks_rc_file =
  Config.local_dir_rc_file (Printf.sprintf "%s.bookmarks" factory_name)

let default_word_re = "[a-zA-Z0-9]+"

let group = ref Ocf.group
let add_to_group path o = group := Ocf.add !group path o
let group () = !group

open Tsdl

let default_key_bindings  =
  Rc.to_keystates_with_mask
    [
      [0, Sdl.Kmod.ctrl, Sdl.K.x ; 0, 0, Sdl.K.b], factory_name^"_switch_buffer" ;
      [0, Sdl.Kmod.ctrl, Sdl.K.x ; 0, 0, Sdl.K.k], factory_name^"_destroy_buffer" ;
      [0, Sdl.Kmod.(alt + shift), Sdl.K.percent], factory_name^"_query_replace" ;
      [0, Sdl.Kmod.(ctrl + alt + shift), Sdl.K.percent], factory_name^"_query_replace_re" ;
      [0, Sdl.Kmod.ctrl, Sdl.K.s], factory_name^"_search" ;
      [0, Sdl.Kmod.ctrl, Sdl.K.r], factory_name^"_search_backward" ;
      [0, Sdl.Kmod.(ctrl + alt), Sdl.K.s], factory_name^"_search_re" ;
      [0, Sdl.Kmod.(ctrl + alt), Sdl.K.r], factory_name^"_search_re_backward" ;
      [0, 0, Sdl.K.escape; 0, Sdl.Kmod.shift, Sdl.K.slash], factory_name^"_expand";
      [0, Sdl.Kmod.shift, Sdl.K.escape; 0, Sdl.Kmod.shift, Sdl.K.slash], factory_name^"_expand";
      [0, Sdl.Kmod.ctrl, Sdl.K.z], factory_name^"_undo" ;
      [0, Sdl.Kmod.(ctrl + alt), Sdl.K.z], factory_name^"_redo" ;
      [Sdl.Kmod.shift, 0, Sdl.K.home], factory_name^"_beginning_of_line" ;
      [Sdl.Kmod.shift, 0, Sdl.K.kend], factory_name^"_end_of_line" ;
      [Sdl.Kmod.shift, Sdl.Kmod.ctrl, Sdl.K.a], factory_name^"_beginning_of_line" ;
      [Sdl.Kmod.shift, Sdl.Kmod.ctrl, Sdl.K.e], factory_name^"_end_of_line" ;
      [0, Sdl.Kmod.ctrl, Sdl.K.k], factory_name^"_kill_line" ;
      [0, Sdl.Kmod.ctrl, Sdl.K.delete], factory_name^"_kill_word" ;
      [0, Sdl.Kmod.ctrl, Sdl.K.backspace], factory_name^"_backward_kill_word" ;
      [Sdl.Kmod.shift, Sdl.Kmod.ctrl, Sdl.K.left], factory_name^"_backward_word" ;
      [Sdl.Kmod.shift, Sdl.Kmod.ctrl, Sdl.K.right], factory_name^"_forward_word" ;
      [Sdl.Kmod.shift, 0, Sdl.K.up], factory_name^"_backward_line" ;
      [Sdl.Kmod.shift, 0, Sdl.K.down], factory_name^"_forward_line" ;
      [Sdl.Kmod.shift, 0, Sdl.K.left], factory_name^"_backward_char" ;
      [Sdl.Kmod.shift, 0, Sdl.K.right], factory_name^"_forward_char" ;
      [0, 0, Sdl.K.escape ; 0, 0, Sdl.K.y], factory_name^"_yank_choose" ;
      [0, Sdl.Kmod.alt, Sdl.K.g], factory_name^"_goto_line" ;
      [0, Sdl.Kmod.ctrl, Sdl.K.d], factory_name^"_delete_char" ;
      [0, 0, Sdl.K.backspace], factory_name^"_backward_delete_char" ;
      [0, Sdl.Kmod.ctrl, Sdl.K.t], factory_name^"_transpose_chars" ;
      [0, Sdl.Kmod.ctrl, Sdl.K.x; 0, Sdl.Kmod.ctrl, Sdl.K.l], factory_name^"_transpose_lines" ;
      [0, 0, Sdl.K.escape; 0, 0, Sdl.K.t], factory_name^"_transpose_words" ;
      [0, Sdl.Kmod.ctrl, Sdl.K.x ; 0, Sdl.Kmod.ctrl, Sdl.K.b], factory_name^"_set_bookmark" ;
      [0, Sdl.Kmod.ctrl, Sdl.K.l ; 0, 0, Sdl.K.p], factory_name^"_push_location" ;
      [0, Sdl.Kmod.ctrl, Sdl.K.l ; 0, 0, Sdl.K.o], factory_name^"_pop_location" ;
      [0, Sdl.Kmod.ctrl, Sdl.K.l ; 0, 0, Sdl.K.f], factory_name^"_forward_location" ;
      [0, Sdl.Kmod.ctrl, Sdl.K.m ; 0, Sdl.Kmod.ctrl, Sdl.K.v], "multiclip_"^factory_name^"_paste" ;
    ]

let key_bindings =
  let o = Ocf.list Config.binding_wrappers ~doc:"Key bindings"
    default_key_bindings
  in
  add_to_group ["key_bindings"] o;
  o

let default_filename_language_patterns =
  [
    ".*\\.ml[iyl]?$", "text/x-ocaml" ;
    ".*\\.c$",        "text/x-c" ;
    ".*\\.cpp$",      "text/x-cpp" ;
    ".*\\.c#$",       "text/x-csharp" ;
    ".*\\.css$",      "text/css";
    ".*\\.less$",      "text/css";
    ".*\\.py$",       "text/x-python" ;
    ".*\\.pl$",       "text/x-perl" ;
    ".*\\.tex$",      "text/x-tex" ;
    ".*\\.htm[l]?$",  "text/html" ;
    ".*\\.xml$",      "text/xml" ;
    ".*Makefile\\(\\.in\\)?$", "text/x-makefile" ;
    ".*ChangeLog$",   "text/x-changelog" ;
    ".*\\.sh\\(\\.in\\)?$",   "text/x-shellscript" ;
    ".*\\configure\\(\\.in\\)?$",   "text/x-shellscript" ;
  ]

let filename_language_patterns =
  let o = Ocf.list Ocf.Wrapper.(pair string string)
  ~doc:("Associations between regular expressions on filename and the "^
     "mime type used to get the language highlight to use in buffer")
      default_filename_language_patterns
  in
  add_to_group ["language_mime_from_filename_patterns"] o;
  o

let default_filename_mode_patterns =
  [
    ".*\\.ml[iyl]?$", "ocaml" ;
    ".*Makefile\\(\\.in\\)?$", "makefile" ;
    ".*ChangeLog$", "changelog";
  ]

let filename_mode_patterns =
  let o = Ocf.list Ocf.Wrapper.(pair string string)
    ~doc:("Associations between regular expressions on filename and the "^
     "name of the sourceview mode to use in buffer")
      default_filename_mode_patterns
  in
  add_to_group ["mode_from_filename_patterns"] o;
  o

let default_max_undo_levels = 200
let max_undo_levels =
  let o = Ocf.int ~doc:"Maximum undo levels in each sourceview buffer"
    default_max_undo_levels
  in
  add_to_group ["max_undo_levels"] o;
  o


let default_wrap_mode =
  let o = Ocf.option Stk.Textview.wrap_mode_wrapper
    ~doc:"Default wrap mode to use when creating a sourceview (char, word, or none)"
    Stk.Textview.Wrap_char
  in
  add_to_group ["default_wrap_mode"] o;
  o

let default_theme =
  let o = Ocf.string ~doc:"Default theme for sourceviews" "default" in
  add_to_group ["default_theme"] o;
  o

let read () = Ocf.from_file (group()) rc_file
let write () = Ocf.to_file (group()) rc_file

let (add_sourceview_key_binding, add_sourceview_key_binding_string) =
  Commands.create_add_binding_commands key_bindings factory_name

let create_add_sourceview_mode_binding_commands option mode_name =
  Commands.create_add_binding_commands option
    (Printf.sprintf "%s_mode_%s" factory_name mode_name)