153 lines
5.9 KiB
OCaml
153 lines
5.9 KiB
OCaml
(*
|
|
* uTop.ml
|
|
* -------
|
|
* Copyright : (c) 2011, Jeremie Dimino <jeremie@dimino.org>
|
|
* Licence : BSD3
|
|
*
|
|
* This file is a part of utop.
|
|
*)
|
|
|
|
open CamomileLibraryDyn.Camomile
|
|
open Lwt_react
|
|
open LTerm_text
|
|
open LTerm_geom
|
|
open LTerm_style
|
|
|
|
module String_set = Set.Make(String)
|
|
|
|
(* +-----------------------------------------------------------------+
|
|
| Keywords |
|
|
+-----------------------------------------------------------------+ *)
|
|
|
|
let default_keywords = [
|
|
"and"; "as"; "assert"; "begin"; "class"; "constraint"; "do";
|
|
"done"; "downto"; "else"; "end"; "exception"; "external";
|
|
"for"; "fun"; "function"; "functor"; "if"; "in"; "include";
|
|
"inherit"; "initializer"; "lazy"; "let"; "match"; "method"; "module";
|
|
"mutable"; "new"; "object"; "of"; "open"; "private"; "rec"; "sig";
|
|
"struct"; "then"; "to"; "try"; "type"; "val"; "virtual";
|
|
"when"; "while"; "with"; "try_lwt"; "finally"; "for_lwt"; "lwt";
|
|
]
|
|
|
|
let keywords = ref (List.fold_left (fun set kwd -> String_set.add kwd set) String_set.empty default_keywords)
|
|
let add_keyword kwd = keywords := String_set.add kwd !keywords
|
|
|
|
(* +-----------------------------------------------------------------+
|
|
| Prompts |
|
|
+-----------------------------------------------------------------+ *)
|
|
|
|
let size = UTop_private.size
|
|
|
|
let count = UTop_private.count
|
|
|
|
let make_prompt count size =
|
|
let tm = Unix.localtime (Unix.time ()) in
|
|
let txt =
|
|
eval [
|
|
B_bold true;
|
|
B_fg lcyan;
|
|
S "─( ";
|
|
B_fg lmagenta; S(Printf.sprintf "%02d:%02d:%02d" tm.Unix.tm_hour tm.Unix.tm_min tm.Unix.tm_sec); E_fg;
|
|
S " )─< ";
|
|
B_fg lyellow; S(Printf.sprintf "command %d" count); E_fg;
|
|
S " >─";
|
|
] in
|
|
Array.append (
|
|
if Array.length txt > size.cols then
|
|
Array.sub txt 0 size.cols
|
|
else
|
|
Array.append txt (Array.make (size.cols - Array.length txt) (UChar.of_int 0x2500, { none with foreground = Some lcyan; bold = Some true }))
|
|
) [|(UChar.of_char '#', { none with foreground = Some lgreen }); (UChar.of_char ' ', none)|]
|
|
|
|
let prompt = ref (S.l2 make_prompt count size)
|
|
|
|
let prompt_continue = ref (S.const [|(UChar.of_char '>', { none with foreground = Some lgreen }); (UChar.of_char ' ', LTerm_style.none)|])
|
|
let prompt_comment = ref (S.const [|(UChar.of_char '*', { none with foreground = Some lgreen }); (UChar.of_char ' ', LTerm_style.none)|])
|
|
|
|
(* +-----------------------------------------------------------------+
|
|
| Help |
|
|
+-----------------------------------------------------------------+ *)
|
|
|
|
module Bindings = Zed_input.Make (LTerm_key)
|
|
module Keys_map = Map.Make (struct type t = LTerm_key.t list let compare = compare end)
|
|
|
|
let () =
|
|
Hashtbl.add Toploop.directive_table "utop_help"
|
|
(Toploop.Directive_none
|
|
(fun () ->
|
|
print_endline "You can use the following commands to get more help:
|
|
|
|
#utop_bindings : list all the current key bindings
|
|
"));
|
|
|
|
Hashtbl.add Toploop.directive_table "utop_bindings"
|
|
(Toploop.Directive_none
|
|
(fun () ->
|
|
let make_lines keys actions acc =
|
|
match actions with
|
|
| [] ->
|
|
(String.concat " " (List.map LTerm_key.to_string_compact keys),
|
|
"",
|
|
"does nothing")
|
|
:: acc
|
|
| action :: actions ->
|
|
let rec loop actions acc =
|
|
match actions with
|
|
| [] ->
|
|
acc
|
|
| action :: actions ->
|
|
loop
|
|
actions
|
|
(("",
|
|
LTerm_read_line.name_of_action action,
|
|
LTerm_read_line.doc_of_action action)
|
|
:: acc)
|
|
in
|
|
loop
|
|
actions
|
|
((String.concat " " (List.map LTerm_key.to_string_compact keys),
|
|
LTerm_read_line.name_of_action action,
|
|
LTerm_read_line.doc_of_action action)
|
|
:: acc)
|
|
in
|
|
let bindings = Bindings.fold (fun key actions map -> Keys_map.add key (List.map (fun action -> (LTerm_read_line.Edit action)) actions) map) !LTerm_edit.bindings Keys_map.empty in
|
|
let bindings = Bindings.fold Keys_map.add !LTerm_read_line.bindings bindings in
|
|
let table = List.rev (Keys_map.fold (fun keys action acc -> make_lines keys action acc) bindings []) in
|
|
let size_key, size_name, size_doc =
|
|
List.fold_left
|
|
(fun (size_key, size_name, size_doc) (key, name, doc) ->
|
|
(max (String.length key) size_key,
|
|
max (String.length name) size_name,
|
|
max (String.length doc) size_doc))
|
|
(0, 0, 0)
|
|
table
|
|
in
|
|
let buf = Buffer.create 128 in
|
|
let format_line (key, name, doc) =
|
|
Buffer.clear buf;
|
|
Buffer.add_string buf key;
|
|
while Buffer.length buf < size_key do
|
|
Buffer.add_char buf ' '
|
|
done;
|
|
Buffer.add_string buf " : ";
|
|
Buffer.add_string buf name;
|
|
while Buffer.length buf < size_key + size_name + 3 do
|
|
Buffer.add_char buf ' '
|
|
done;
|
|
Buffer.add_string buf " -> ";
|
|
Buffer.add_string buf doc;
|
|
Buffer.add_char buf '\n';
|
|
output_string stdout (Buffer.contents buf)
|
|
in
|
|
List.iter format_line table;
|
|
flush stdout))
|
|
|
|
(* +-----------------------------------------------------------------+
|
|
| Initialization |
|
|
+-----------------------------------------------------------------+ *)
|
|
|
|
let () =
|
|
(* Do not load packages linked with the toplevel. *)
|
|
Topfind.don't_load_deeply ["utop"; "findlib"; "lambda-term"]
|
|
|