In an OCaml custom toplevel, is there a way to programatically set the prompt from # to something else? I would like to be able to change it in response to the user's last one of my custom functions (kinda like in bash how you can set PS1). I can't even find a #directive to change it. Thanks!
            Asked
            
        
        
            Active
            
        
            Viewed 576 times
        
    6
            
            
        
        Gaius
        
- 2,556
 - 1
 - 24
 - 43
 
1 Answers
9
            In toplevel/toploop.ml:
let prompt =
  if !Clflags.noprompt then ""
  else if !first_line then "# "
  else if Lexer.in_comment () then "* "
  else "  "
in
But wait! The computed prompt is passed to !read_interactive_input,
and this reference is exported:
In toplevel/toploop.mli:
(* Hooks for external line editor *)
val read_interactive_input : (string -> string -> int -> int * bool) ref
So it would seem that all you have to do is change the value of Toploop.read_interactive_input from its default to a function that ignores the passed prompt and prints the one you want instead.
The default value for read_interactive_input is:
let read_input_default prompt buffer len =
  output_string Pervasives.stdout prompt; flush Pervasives.stdout;
  let i = ref 0 in
  try
    while true do
      if !i >= len then raise Exit;
      let c = input_char Pervasives.stdin in
      buffer.[!i] <- c;
      incr i;
      if c = '\n' then raise Exit;
    done;
    (!i, false)
  with
  | End_of_file ->
      (!i, true)
  | Exit ->
      (!i, false)
So you can use:
# let my_read_input prompt buffer len =
  output_string Pervasives.stdout  "%%%" ; flush Pervasives.stdout;
  let i = ref 0 in
  try
    while true do
      if !i >= len then raise Exit;
      let c = input_char Pervasives.stdin in
      buffer.[!i] <- c;
      incr i;
      if c = '\n' then raise Exit;
    done;
    (!i, false)
  with
  | End_of_file ->
      (!i, true)
  | Exit ->
      (!i, false)
                                  ;;
val my_read_input : 'a -> string -> int -> int * bool = <fun>
# Toploop.read_interactive_input := my_read_input ;;
- : unit = ()
%%%
        Pascal Cuoq
        
- 79,187
 - 7
 - 161
 - 281
 
- 
                    1BTW [this](http://gaiustech.wordpress.com/2011/05/28/ociml-minor-updates/) is what it was for. – Gaius May 28 '11 at 15:22
 - 
                    2Or, shorter and slightly more "chainable": `Toploop.read_interactive_input := let old = !Toploop.read_interactive_input in fun prompt buffer len -> old "%%%" buffer len ;;` – Pascal Cuoq May 30 '11 at 07:17