
/******************************************************************************
* MODULE     : edit_session.gen.cc
* DESCRIPTION: input and output handling for programming sessions
* COPYRIGHT  : (C) 1999  Joris van der Hoeven
*******************************************************************************
* This software falls under the GNU general public license and comes WITHOUT
* ANY WARRANTY WHATSOEVER. See the file $TEXMACS_PATH/LICENSE for more details.
* If you don't have this file, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
******************************************************************************/

#include <Process/edit_process.gen.h>
#include <list.gen.h>
#include <connect.gen.h>

#module code_edit_session
#import edit_process
#import list (path)
#import connect

/******************************************************************************
* Other useful subroutines
******************************************************************************/

static bool
is_empty (tree t) {
  if (is_atomic (t)) return (t == "");
  if (is_expand (t, "math", 1)) return is_empty (t[1]);
  if (is_document (t) || is_concat (t)) {
    int i;
    for (i=0; i<N(t); i++)
      if (!is_empty (t[i])) return FALSE;
    return TRUE;
  }
  return FALSE;
}

/******************************************************************************
* Routines for sessions
******************************************************************************/

void
edit_process_rep::make_session (string lan, string session) {
  /* These two lines will become obsolete */
  if (make_return_after ()) return;
  if (make_return_before ()) return;
  /* -------------------------------------*/

  tree body (DOCUMENT, "");
  path p (3, path (0, 0));
  insert_tree (tree (EXPAND, "session", lan, session, body), p);
  if (lan == "shell") start_input ();
  else if (connection_declared (lan)) connect ();
  else start_input ();
}

void
edit_process_rep::start_input () {
  path p;
  bool needs_return= FALSE;
  if (!nil (p= search_upwards_expand ("input"))) {
    go_to (p * 1);
    needs_return= TRUE;
  }
  else if (!nil (p= search_upwards_expand ("output"))) {
    tree st= subtree (et, p);
    if ((N(st) == 2) && is_empty (st [1])) {
      cut (p);
      remove_backwards ();
    }
    else go_to (p * 1);
    needs_return= TRUE;
  }

  string lan   = get_env_string (PROG_LANGUAGE);
  string session= get_env_string (THIS_SESSION);
  tree   prompt = "";
  tree   input  = "";

  if (connection_declared (lan)) {
    prompt = connection_read (lan, session, 0, "prompt");
    input  = connection_read (lan, session, 0, "input");
  }
  while (is_document (prompt))
    if (N(prompt) == 0) prompt= "";
    else prompt= prompt[0];
  if (prompt == "") prompt= lan * "] ";
  if (!is_document (input)) input= tree (DOCUMENT, input);
  if (math_input) input= tree (VAR_EXPAND, "math", input);

  path q = path_up (tp, 2);
  int  i = last_item (path_up (tp));
  tree st= subtree (et, q);
  if (is_document (st) &&
      (i+1 < N(st)) &&
      is_expand (st[i+1], "input", 2))
    {
      if (is_empty (input)) {
	tree old= copy (st[i+1][2]);
	if (!(math_input ^ is_expand (old, "math", 1))) input= old;
      }
      assign (q * (i+1), tree (EXPAND, "input", prompt, input));
      go_to (q * path (i+1, 2, end (input)));
    }
  else {
    if (needs_return) insert_return ();
    insert_tree (tree (EXPAND, "input", prompt, input), path (2, end (input)));
  }
  if (message_l != "") {
    set_message (message_l, message_r);
    message_l= "";
    message_r= "";
  }
  else set_message ("", "");
}

void
edit_process_rep::start_output () {
  path p;
  bool needs_return= FALSE;
  if (!nil (p= search_upwards_expand ("input"))) {
    go_to (p * 1);
    needs_return= TRUE;
  }
  else if (!nil (p= search_upwards_expand ("output"))) {
    go_to (p * 1);
    needs_return= TRUE;
  }

  path q = path_up (tp, 2);
  int  i = last_item (path_up (tp));
  tree st= subtree (et, q);
  if (is_document (st) &&
      (i+1 < N(st)) &&
      is_expand (st[i+1], "output", 1))
    {
      assign (q * (i+1), tree (EXPAND, "output", tree (DOCUMENT, "")));
      go_to (q * path (i+1, 1, 0, 0));
    }
  else {
    if (needs_return) insert_return ();
    insert_tree (tree (EXPAND, "output", tree (DOCUMENT, "")),
		 path (1, path (0, 0)));
  }
}

void
edit_process_rep::session_message (string l, string r) {
  message_l= l;
  message_r= r;
}

void
edit_process_rep::session_use_math_input (bool flag) {
  if (math_input != flag) {
    math_input= flag;
    path p= search_upwards_expand ("input");
    if (nil (p)) return;
    tree input (DOCUMENT, "");
    path q (0, 0);
    if (math_input) {
      input= tree (VAR_EXPAND, "math", input);
      q= path (1, q);
    }
    assign (p * 2, input);
    go_to (p * path (2, q));
  }
}

/******************************************************************************
* Cursor movement inside sessions
******************************************************************************/

void
edit_process_rep::session_var_go_up () {
  path p= search_upwards_expand ("session");
  if (nil (p) || (N(p)+2 > N(tp))) return;
  tree st= subtree (et, p);
  if ((N(st) != 4) || (tp[N(p)]!=3) || (!is_document (st[3]))) return;
  int i= tp[N(p)+1];
  p= p * 3;
  st= st[3];
  for (i--; i>=0; i--)
    if (is_expand (st[i], "input", 2)) {
      go_to (p * path (i, 2, end (st[i][2])));
      select_from_cursor_if_active ();
      return;
    }
}

void
edit_process_rep::session_var_go_down () {
  path p= search_upwards_expand ("session");
  if (nil (p) || (N(p)+2 > N(tp))) return;
  tree st= subtree (et, p);
  if ((N(st) != 4) || (tp[N(p)]!=3) || (!is_document (st[3]))) return;
  int i= tp[N(p)+1];
  p= p * 3;
  st= st[3];
  for (i++; i<N(st); i++)
    if (is_expand (st[i], "input", 2)) {
      go_to (p * path (i, 2, end (st[i][2])));
      select_from_cursor_if_active ();
      return;
    }
}

void
edit_process_rep::session_go_left () {
  path p= search_upwards_expand ("input");
  if (nil (p)) return;
  int i= tp[N(p)];
  path old_tp= tp;
  go_left ();
  p= search_upwards_expand ("input");
  if (nil (p) || ((tp[N(p)] != 2) && (tp[N(p)] != i))) go_to (old_tp);
  select_from_cursor_if_active ();
}

void
edit_process_rep::session_go_right () {
  path p= search_upwards_expand ("input");
  if (nil (p)) return;
  int i= tp[N(p)];
  path old_tp= tp;
  go_right ();
  p= search_upwards_expand ("input");
  if (nil (p) || ((tp[N(p)] != 2) && (tp[N(p)] != i))) go_to (old_tp);
  select_from_cursor_if_active ();
}

void
edit_process_rep::session_go_up () {
  path p= search_upwards_expand ("input");
  if (nil (p)) return;
  int i= tp[N(p)];
  path old_tp= tp;
  go_up ();
  p= search_upwards_expand ("input");
  if (nil (p) || ((tp[N(p)] != 2) && (tp[N(p)] != i))) {
    go_to (old_tp);
    session_var_go_up ();
  }
  select_from_cursor_if_active ();
}

void
edit_process_rep::session_go_down () {
  path p= search_upwards_expand ("input");
  if (nil (p)) return;
  int i= tp[N(p)];
  path old_tp= tp;
  go_down ();
  p= search_upwards_expand ("input");
  if (nil (p) || ((tp[N(p)] != 2) && (tp[N(p)] != i))) {
    go_to (old_tp);
    session_var_go_down ();
  }
  select_from_cursor_if_active ();
}

void
edit_process_rep::session_go_page_up () {
  int i;
  for (i=0; i<5; i++)
    session_var_go_up ();
}

void
edit_process_rep::session_go_page_down () {
  int i;
  for (i=0; i<5; i++)
    session_var_go_down ();
}

void
edit_process_rep::session_remove_backwards () {
  path p= search_upwards_expand ("math");
  if (nil (p)) {
    p= search_upwards_expand ("input");
    if (nil (p) || (tp == start (et, p * 2))) return;
  }
  else if (tp == start (et, p * 1)) return;
  remove_backwards ();
}

void
edit_process_rep::session_remove_forwards () {
  path p= search_upwards_expand ("math");
  if (nil (p)) {
    p= search_upwards_expand ("input");
    if (nil (p) || (tp == end (et, p * 2))) return;
  }
  else if (tp == end (et, p * 1)) return;
  remove_forwards ();
}

/******************************************************************************
* Manipulating the input line
******************************************************************************/

string
edit_process_rep::session_get_input () {
  return "";
}

int
edit_process_rep::session_get_input_pos () {
  return 0;
}

void
edit_process_rep::session_set_input (string s) {
  (void) s;
}

void
edit_process_rep::session_set_input_pos (int pos) {
  (void) pos;
}

#endmodule // code_edit_session
