%   Borland-like IDE Mode for JED	-*- SLang -*-
%
%   Put the line: () = evalfile ("ide.sl");
%   in your jed.rc startup file.
%
%   Written by Guido Gonzato <guido@ibogeo.df.unibo.it>;
%   based on John E. Davis' original wordstar.sl.
%
%   This file makes jed a jolly good 99% compatible with the true-blue
%   WordStar, jstar, the DOS editor, and the good old Borland IDE.
%   Some Emacs compatibility is maintained: blocks are actually "regions"
%   as in Emacs mode; ^X and ^C are not redefined.
%
%   Please send me requests and bug reports, should you find any.
%   Version 1.2.0; for jed B0.99.9 upwards.
%
%   Version 1.2.8; for jed B0.99.10 upwards.
%   Last modified: 18 May 2000

Help_File = "ide.hlp";

%
%  Key definitions for Linux and DOS/Windows.
%

#ifdef IBMPC_SYSTEM

static variable Key_F1         = "^@;";
static variable Key_F2         = "^@<";
static variable Key_F3         = "^@=";
static variable Key_F4         = "^@>";
static variable Key_F5         = "^@?";
static variable Key_F6         = "^@@";
static variable Key_F7         = "^@A";
static variable Key_F8         = "^@B";
static variable Key_F9         = "^@C";
static variable Key_F10        = "^@D";
static variable Key_Ins        = "\xE0R";
static variable Key_Del        = "\xE0S";
static variable Key_Home       = "\xE0G";
static variable Key_End        = "\xE0O";
static variable Key_PgUp       = "\xE0I";
static variable Key_PgDown     = "\xE0Q";
static variable Key_ArUp       = "\xE0H";
static variable Key_ArDown     = "\xE0P";
static variable Key_ArRight    = "\xE0M";
static variable Key_ArLeft     = "\xE0K";
static variable Key_Alt_F3	= "^@j";
static variable Key_Alt_F7	= "^@n";
static variable Key_Alt_F8	= "^@o";
static variable Key_BS		= "^?";
static variable Key_Alt_BS	= strcat("\e", Key_BS);

#else % Linux assumed

$1 = "at386 qansi-m vt100 vt102 vt200 vt220 vt300 vt320 vt420 rxvt xterm xterm-color";
$2 = getenv ("TERM");
if ($2 == NULL)
  $2 = "unknown";

static variable Is_Xjed = is_defined ("x_server_vendor");

static define setkey_via_terminfo (tc, def)
{
   if (Is_Xjed)
     return def;

#ifexists get_termcap_string
   variable s = get_termcap_string (tc);
   if (s == "")
     return def;
   return s;
#else
   return def;
#endif
}


static variable Key_F1	= setkey_via_terminfo ("k1",	"^[[11~");
static variable Key_F2	= setkey_via_terminfo ("k2",	"^[[12~");
static variable Key_F3	= setkey_via_terminfo ("k3",	"^[[13~");
static variable Key_F4	= setkey_via_terminfo ("k4",	"^[[14~");
static variable Key_F5	= setkey_via_terminfo ("k5",	"^[[15~");
static variable Key_F6	= setkey_via_terminfo ("k6",	"^[[17~");
static variable Key_F7	= setkey_via_terminfo ("k7",	"^[[18~");
static variable Key_F8	= setkey_via_terminfo ("k8",	"^[[19~");
static variable Key_F9	= setkey_via_terminfo ("k9",	"^[[20~");
static variable Key_F10	= setkey_via_terminfo ("k;",	"^[[21~");

static variable Key_Ins		= setkey_via_terminfo ("kI", "^[[2~");
static variable Key_Del		= setkey_via_terminfo ("kD", "^[[3~");
static variable Key_Home	= setkey_via_terminfo ("kh", "^[[1~");
static variable Key_End		= setkey_via_terminfo ("@7", "^[[4~");
static variable Key_PgUp	= setkey_via_terminfo ("kP", "^[[5~");
static variable Key_PgDown	= setkey_via_terminfo ("kN", "^[[6~");
static variable Key_ArUp	= setkey_via_terminfo ("ku", "^[[A");
static variable Key_ArDown	= setkey_via_terminfo ("kd", "^[[B");
static variable Key_ArRight	= setkey_via_terminfo ("kr", "^[[C");
static variable Key_ArLeft	= setkey_via_terminfo ("kl", "^[[D");
static variable Key_BS		= setkey_via_terminfo ("kb", "^?");

static variable Key_BS_Del	= "^?";

static variable Key_Alt_F3	= strcat("\e", Key_F3);
static variable Key_Alt_BS	= strcat("\e", Key_BS);
static variable Key_Alt_F7	= strcat("\e", Key_F7);
static variable Key_Alt_F8	= strcat("\e", Key_F8);
static variable Key_Alt_BS_Del	= strcat("\e", Key_BS_Del);

#endif % not IBMPC_SYSTEM

static variable Ide_Bookmark_Exist = 1;
set_status_line (" Jed %v: %b (%m%n) (%p %c) %t", 1);
set_abort_char (7); % ^G. Note - wordstar.sl uses ^^.
% ESC ESC ESC (like Emacs) can also be used.

unsetkey ("^B");
unsetkey ("^F");
unsetkey ("^K");
unsetkey ("^P");
unsetkey ("^U");
unsetkey ("^V");
unsetkey ("^W");
unsetkey (Key_F1); % prevent EDT error in xterm
unsetkey (Key_F2);
unsetkey (Key_F3);
unsetkey (Key_F4);
unsetkey (Key_Del);
unsetkey (Key_ArUp);	% arrows keys are redefined to add the
unsetkey (Key_ArDown);	% "goto previous position" feature
unsetkey (Key_ArLeft);
unsetkey (Key_ArRight);
unsetkey (Key_PgUp);
unsetkey (Key_PgDown);
%
% Basic commands: cursor movement, delete, search & replace, etc.
%
setkey ("begin_macro", "\e(");
setkey ("compile", Key_F9);
setkey ("backward_delete_char", Key_BS);
setkey ("dabbrev", "^V");
setkey ("delete_char_cmd", "\eg");	% ^G is used for break
setkey ("delete_char_cmd", Key_Del);
setkey ("delete_line", "^Y");
setkey ("end_macro", "\e)");
setkey ("execute_macro", "\er");
setkey ("format_paragraph", "^B");
setkey ("ide_better_help", Key_F1);
setkey ("ide_toggle_overwrite", Key_Ins);
setkey ("undo", "^U");
setkey ("kbd_quit", "\e\e\e");
setkey ("ide_bdelete_word", Key_Alt_BS);
setkey ("list_buffers", "\e0");
#ifndef IBMPC_SYSTEM
setkey ("ide_bdelete_word", Key_Alt_BS_Del);
#endif
setkey ("ide_bdelete_word", "\et");	%  ESC-o is used for Mode menu
setkey ("ide_bskip_word", "^A");
setkey ("ide_delete_word", "^T");
setkey ("ide_next_char_cmd", "^D");
setkey ("ide_next_char_cmd", Key_ArRight);
setkey ("ide_next_line_cmd", "^Z");	% formerly ^X
setkey ("ide_next_line_cmd", Key_ArDown);
setkey ("ide_page_down", "^C^C");	% formerly ^C
setkey ("ide_page_down", Key_PgDown);
setkey ("ide_page_up", "^R");
setkey ("ide_page_up", Key_PgUp);
setkey ("ide_previous_char_cmd", "^S");
setkey ("ide_previous_char_cmd", Key_ArLeft);
setkey ("ide_previous_line_cmd", "^E");
setkey ("ide_previous_line_cmd", Key_ArUp);
setkey ("ide_repeat_search", "^L");
setkey ("ide_skip_word", "^F");
setkey ("ide_window_down", "^X^X");
setkey ("ide_window_up", "^W");
setkey ("ide_insert_any_char", "^P");
%
% Control-Q keys  --- hope you figure out how to pass ^Q/^S through system
% In case you *cannot* figure out how, you can use ESC+^key instead of ^Q; 
% for instance, ESC-^Y acts as ^Q-Y. Twisted, but some terminals need it.
% There's an exception: use ESC + ESC + digit to mimick ^Q + digit; this is
% to avoid overriding the ESC + number + operation feature.
%
setkey (".0 ide_goto_mark_n", "^Q0");
setkey (".1 ide_goto_mark_n", "^Q1");
setkey (".2 ide_goto_mark_n", "^Q2");
setkey (".3 ide_goto_mark_n", "^Q3");
setkey (".4 ide_goto_mark_n", "^Q4");
setkey (".5 ide_goto_mark_n", "^Q5");
setkey (".6 ide_goto_mark_n", "^Q6");
setkey (".7 ide_goto_mark_n", "^Q7");
setkey (".8 ide_goto_mark_n", "^Q8");
setkey (".9 ide_goto_mark_n", "^Q9");
#ifndef MSDOS WIN32
setkey (".0 ide_goto_mark_n", "\e\e0");
setkey (".1 ide_goto_mark_n", "\e\e1");
setkey (".2 ide_goto_mark_n", "\e\e2");
setkey (".3 ide_goto_mark_n", "\e\e3");
setkey (".4 ide_goto_mark_n", "\e\e4");
setkey (".5 ide_goto_mark_n", "\e\e5");
setkey (".6 ide_goto_mark_n", "\e\e6");
setkey (".7 ide_goto_mark_n", "\e\e7");
setkey (".8 ide_goto_mark_n", "\e\e8");
setkey (".9 ide_goto_mark_n", "\e\e9");
#endif
setkey ("kill_line", "^QY");
setkey ("kill_line", "^Q^Y");
setkey ("ide_bob", "^QR");
setkey ("ide_bob", "^Q^R");
setkey ("ide_bol", "^QS");
setkey ("ide_bol", "^Q^S");
setkey ("ide_bol", Key_Home);
setkey ("ide_eob", "^QC");
setkey ("ide_eob", "^Q^C");
setkey ("ide_eol", "^QD");
setkey ("ide_eol", "^Q^D");
setkey ("ide_eol", Key_End);
setkey ("ide_goto_begin_block", "^QB");
setkey ("ide_goto_begin_block", "^Q^B");
setkey ("ide_goto_bottom_of_window", "^QX");
setkey ("ide_goto_bottom_of_window", "^Q^X");
setkey ("ide_goto_end_block", "^QK");
setkey ("ide_goto_end_block", "^Q^K");
setkey ("ide_goto_line_cmd", "^QI");
setkey ("ide_goto_line_cmd", "^Q^I");
setkey ("ide_goto_middle_of_window", "^QM");
setkey ("ide_goto_prev", "^QP");
setkey ("ide_goto_top_of_window", "^QE");
setkey ("ide_goto_top_of_window", "^Q^E");
setkey ("ide_replace_cmd", "^QA");
setkey ("ide_replace_cmd", "^Q^A");
setkey ("ide_search_forward", "^QF");
setkey ("ide_search_forward", "^Q^F");
setkey ("ide_toggle_case", "^QT");
setkey ("ide_toggle_case", "^Q^T");
#ifndef MSDOS WIN32
setkey ("kill_line", "\e^Y");
setkey ("ide_bob", "\e^R");
setkey ("ide_bol", "\e^S");
setkey ("ide_eob", "\e^C");
setkey ("ide_eol", "\e^D");
setkey ("ide_goto_begin_block", "\e^B");
setkey ("ide_goto_bottom_of_window", "\e^X");
setkey ("ide_goto_end_block", "\e^K");
setkey ("ide_goto_line_cmd", "\e^I");
setkey ("ide_goto_prev", "\e^P");
setkey ("ide_goto_top_of_window", "\e^E");
setkey ("ide_replace_cmd", "\e^A");
setkey ("ide_search_forward", "\e^F");
setkey ("ide_toggle_case", "\e^T");
#endif
%
% Control-K map
%
setkey (".0 ide_set_mark_n", "^K0");
setkey (".1 ide_set_mark_n", "^K1");
setkey (".2 ide_set_mark_n", "^K2");
setkey (".3 ide_set_mark_n", "^K3");
setkey (".4 ide_set_mark_n", "^K4");
setkey (".5 ide_set_mark_n", "^K5");
setkey (".6 ide_set_mark_n", "^K6");
setkey (".7 ide_set_mark_n", "^K7");
setkey (".8 ide_set_mark_n", "^K8");
setkey (".9 ide_set_mark_n", "^K9");
setkey ("exit_jed", "^KX");
setkey ("exit_jed", "^K^X");
setkey ("find_file", "^KE");
setkey ("find_file", "^K^E");
setkey ("find_file", Key_F3);
setkey ("kill_buffer", "^KQ");
setkey ("kill_buffer", "^K^Q");
setkey ("kill_buffer", Key_Alt_F3);
setkey ("one_window", "^KI");
setkey ("one_window", "^K^I");
setkey ("one_window", Key_F5);
setkey ("save_buffer", "^KD");
setkey ("save_buffer", "^K^D");
setkey ("save_buffer", Key_F2);
setkey ("suspend", "^KZ");
setkey ("suspend", "^K^Z");
setkey ("ide_next_buffer", "^KP");
setkey ("ide_next_buffer", "^K^P");
setkey ("ide_next_buffer", Key_F6);
setkey ("ide_begin_block", "^KB");	% set mark
setkey ("ide_begin_block", "^K^B");
setkey ("ide_copy_block", "^KC");	% yank
setkey ("ide_copy_block", "^K^C");
setkey ("ide_delete_block", "^KY");	% cut
setkey ("ide_delete_block", "^K^Y");
% ^KK, exchange point and mark, is no longer implemented
setkey ("comment_region", "^K;");
setkey ("uncomment_region", "^K:");
setkey ("comment_line", "^C;");
setkey ("uncomment_line", "^C:");
setkey ("ide_filter_region", "^K/");
setkey ("ide_insert_file", "^KR");
setkey ("ide_insert_file", "^K^R");
setkey ("ide_lowercase_region", "^KL");
setkey ("ide_lowercase_region", "^K^L");
setkey ("ide_save_buffer", "^KS");
setkey ("ide_save_buffer", "^K^S");
setkey ("ide_select_word", "^KT");
setkey ("ide_select_word", "^K^T");
setkey ("ide_void_block", "^KK");
setkey ("ide_void_block", "^K^K");
setkey ("ide_clear_block", "^KH");	% copy to the clipboard
setkey ("ide_clear_block", "^K^H");
setkey ("ide_uppercase_region", "^KU");
setkey ("ide_uppercase_region", "^K^U");
setkey ("write_region", "^KW");
setkey ("write_region", "^K^W");
setkey ("reg_insert_register", "^KJ");	% registers are something like
setkey ("reg_insert_register", "^K^J");	% a multiple clipboard
setkey ("reg_copy_to_register", "^KG");
setkey ("reg_copy_to_register", "^K^G");
% compiler/debugger interface
setkey ("compile_parse_errors", Key_Alt_F8);	% ^X'
setkey ("compile_previous_error", Key_Alt_F7);
setkey ("compile_previous_error", "^X,");

%
% Now let's implement the damn thing
%

$1 = 13;

% bookmarks 0..9 are for the user; bookmark 10 is used by some of the
% following functions; bookmark 11 and 12 mark the beginning and end of
% the block (used by ^QB and ^QK)

static variable _Ide_Bookmarks = Mark_Type[$1];

%  ide_set_bookmark () and ide_goto_bookmark () are implemented to provide
%  a more Borland-ish way of copying and moving blocks, and of moving 
%  around generally.

define ide_set_bookmark ()
{
  _Ide_Bookmarks[10] = create_user_mark ();
  Ide_Bookmark_Exist = 1;
}
   
define ide_goto_bookmark ()
{
  variable mrk = _Ide_Bookmarks[10];
  ide_set_bookmark ();
  sw2buf (mrk.buffer_name);
  goto_user_mark (mrk);
}

%
% Basic commands: cursor movement, delete, search & replace, etc.
%

define ide_execute_macro ()		% ESC-R
{
  ide_set_bookmark ();
  call ("execute_macro");
}

define ide_previous_char_cmd ()		% Key_ArLeft
{
  ide_set_bookmark ();
  call ("previous_char_cmd");
}

define ide_next_char_cmd ()		% Key_ArRight
{
  ide_set_bookmark ();
  call ("next_char_cmd");
}

define ide_next_line_cmd ()		% Key_ArDown
{
  ide_set_bookmark ();
  call ("next_line_cmd");
}

define ide_previous_line_cmd ()		% Key_ArUp
{
  ide_set_bookmark ();
  call ("previous_line_cmd");
}

define ide_page_down ()			% Key_PgDown
{
  ide_set_bookmark ();
  call ("page_down");
}

define ide_page_up ()			% Key_PgUp
{
  ide_set_bookmark ();
  call ("page_up");
}

define ide_bob ()			% ^QR
{
  ide_set_bookmark ();
  bob ();
}

define ide_eob ()			% ^QC
{
  ide_set_bookmark ();
  eob ();
}

define ide_bol ()			% Key_Home
{
  ide_set_bookmark ();
  bol ();
}

define ide_eol ()			% Key_End
{
  ide_set_bookmark ();
  eol ();
}

define ide_goto_bottom_of_window ()	% ^QX
{
  ide_set_bookmark ();
  goto_bottom_of_window ();
}

define ide_goto_top_of_window ()	% ^QE
{
  ide_set_bookmark ();
  goto_top_of_window ();
}

define ide_goto_middle_of_window ()	% ^QM
{
  variable top, bottom;
  ide_set_bookmark ();
  goto_top_of_window ();
  top = what_line ();
  goto_bottom_of_window ();
  bottom = what_line ();
  go_up ((bottom - top) / 2);
  goto_column (1);
}

define ide_window_up ()			% ^W
{
  ide_set_bookmark ();
  recenter (window_line() + 1);
}

define ide_window_down ()		% ^Z
{
  ide_set_bookmark ();
  recenter (window_line() - 1);
}

define ide_goto_line_cmd ()		% ^QI
{
  ide_set_bookmark ();
  goto_line_cmd ();
}

define ide_replace_cmd ()		% ^QA
{
  ide_set_bookmark ();
  replace_cmd ();
}

define ide_search_forward ()		% ^QF
{
  ide_set_bookmark ();
  search_forward ();
}

define ide_toggle_case ()		% ^QT
{
  variable on_off;
  CASE_SEARCH = not(CASE_SEARCH);
  if (CASE_SEARCH == 1)
    on_off = "On";
  else
    on_off = "Off";
  vmessage ("Case search is %s ", on_off);
}

define ide_toggle_overwrite ()
{
   toggle_overwrite ();
   if (is_overwrite_mode ())
     message ("Overwrite");
   else
     message ("Insert");
}
  
define ide_repeat_search ()		% ^L
{
  ide_set_bookmark ();
  go_right_1 ();
   !if (fsearch(LAST_SEARCH)) error ("Not found.");
}

define ide_bdelete_word ()		% M-O
{
  variable p = _get_point ();
  ide_set_bookmark ();
  push_mark ();
  bskip_chars ("a-zA-Z0-9");
  if (_get_point () == p) bskip_chars (" \n\t"); 
  if (_get_point () == p) go_left (1);
  del_region ();
}

define ide_bskip_word ()		% ^A
{
  variable p = _get_point ();
  ide_set_bookmark ();
  push_mark ();
  bskip_chars ("\n\t !\"#$%&'()*+,-./:;<=>?@[\]^`{|}~");
  bskip_chars ("^\n\t !\"#$%&'()*+,-./:;<=>?@[\]^`{|}~");
  pop_mark_0 ();
}

define ide_delete_word ()		% ^T
{
  variable p = _get_point ();
  push_mark ();
  skip_chars ("a-zA-Z0-9");
  if (_get_point () == p) skip_chars (" \n\t"); 
  if (_get_point () == p) go_right (1);
  del_region ();
}

define ide_skip_word ()			% ^F
{
  variable p = _get_point ();
  ide_set_bookmark ();
  push_mark ();
  skip_chars ("^\n\t !\"#$%&'()*+,-./:;<=>?@[\]^`{|}~"); 
  if (_get_point () == p) {
    skip_chars ("\n\t !\"#$%&'()*+,-./:;<=>?@[\]^`{|}~");
    skip_chars ("^\n\t !\"#$%&'()*+,-./:;<=>?@[\]^`{|}~"); 
  }
  pop_mark_0 ();
}

define ide_insert_any_char ()		% ^P
{
  variable i, ch = 0, c, msg = "";
  message ("ASCII-");
  update_sans_update_hook (0);
  for (i = 100; i > 0; i = i / 10) {
    vmessage ("ASCII-%s", msg);
    update_sans_update_hook (0);
    do {
      c = getkey ();
    } while ( (c < '0') or (c > '9'));
    ch = ch + i * (c - '0');
    msg += sprintf ("%c", c);
    vmessage ("ASCII-%s", msg);
    update_sans_update_hook (0);
  }
  insert_char (ch);
  vmessage ("ASCII-%s", msg);
}

define ide_next_buffer ()		% Key_F6
{
  variable n, buf, cbuf = whatbuf ();
  n = buffer_list (); % buffers on the stack
  loop (n) {
    buf = ();
    n--;
    if (buf[0] == ' ') continue;
    sw2buf (buf);
    _pop_n (n);
    return;
  }
}

% Blocks: ^K-something
%
% blocks are no longer as in wordstar.sl. We don't cheat anymore. Rather,
% blocks are implemented a la Emacs to maintain compatibility with most .sl
% files (e.g., latex.sl, cmode.sl, etc)

static variable IDE_Block_Buffer = "*ide-clipboard*";
static variable IDE_Block_Buffer_Empty = 1;

define ide_copy_block_to_buffer ()
% paste the new region to the clipboard, then delete the old stuff
{
  setbuf(IDE_Block_Buffer);
  erase_buffer ();
  call ("yank");
}

define ide_begin_block ()		% ^KB
{
  _Ide_Bookmarks[11] = create_user_mark ();
  call ("set_mark_cmd");
}

define ide_end_block ()
{
  _Ide_Bookmarks[12] = create_user_mark ();
  exchange_point_and_mark ();
}

define ide_copy_block ()		% ^KC
{
  ide_set_bookmark ();
  insbuf (IDE_Block_Buffer);
  ide_goto_bookmark ();
}

define ide_goto_begin_block ()		% ^QB
{
  variable mrk = _Ide_Bookmarks[11];
  ide_set_bookmark ();
  sw2buf (mrk.buffer_name);
  ide_set_bookmark ();
  goto_user_mark (mrk);
}

define ide_goto_end_block ()		% ^QK
{
  variable mrk = _Ide_Bookmarks[12];
  ide_set_bookmark ();
  sw2buf (mrk.buffer_name);
  ide_set_bookmark ();
  goto_user_mark (mrk);
}

define ide_void_block ()		% ^KK
{
  pop_mark_0 ();
}

define ide_clear_block ()		% ^KH
{
  ide_end_block ();
  call ("copy_region");			%  copy region to internal buffer  
  ide_copy_block_to_buffer ();
  IDE_Block_Buffer_Empty = 0;
  ide_goto_end_block ();
}

define ide_delete_block ()		% ^KY
{
  ide_clear_block ();        % copy the region to the clipboard, then
  ide_goto_begin_block ();   % redefine the region and delete it. Rather
  ide_begin_block ();        % twisted, but that's the way I like it!
  ide_goto_end_block ();
  ide_end_block ();
  call ("kill_region");
}

define ide_goto_prev ()			% ^QP
{
  if (Ide_Bookmark_Exist != 1) 
    error ("No previous location!");
  ide_goto_bookmark ();
}

define ide_insert_file ()		% ^KR
{
  variable file = 
    read_with_completion ("File:", Null_String, Null_String, 'f');
  ide_set_bookmark ();
  insert_file (file);
  ide_goto_bookmark ();
  message ("File inserted.");
}

define ide_select_word ()		% ^KT, Borland IDE facility
{
  ide_set_bookmark ();
  ide_skip_word ();
  ide_bskip_word ();
  ide_begin_block ();
  ide_skip_word ();
  ide_end_block ();
  ide_goto_bookmark ();
  message ("Word selected.");
}

#ifndef IBMPC_SYSTEM

static variable Last_Process_Command = Null_String;

define ide_filter_region ()		% ^K/, Joe extension
{
  variable cmd, tmp_file;
  ide_end_block ();
  cmd = read_mini ("Pipe to command:", Last_Process_Command, Null_String);
  !if (strlen (cmd)) return;
   
  Last_Process_Command = cmd;
  ide_set_bookmark ();
  tmp_file = make_tmp_file ("/tmp/jedpipe");
  cmd = strcat (cmd, " > ", tmp_file, " 2>&1");

  if (pipe_region (cmd)) {
    error ("Process returned a non-zero exit status.");
  }
 
  () = insert_file (tmp_file);
  ide_begin_block ();
  ide_goto_end_block ();
  ide_end_block ();
  call ("kill_region");
  () = delete_file (tmp_file);
}

#endif

define ide_uppercase_region()		% ^KU
{
  ide_end_block ();
  xform_region('u');
  ide_goto_end_block ();
}
   
define ide_lowercase_region()		% ^KL
{
  ide_end_block ();
  xform_region('d');
  ide_goto_end_block ();
}

% Variables for (un-)commenting lines and regions
%
% There should be a consistent way of commenting/uncommenting regions 
% (not only lines!), but as of B0.99.10 this is lacking. Each mode should
% provide this facility; LaTeX mode is a nice example.
% What follows is a botched attempt at providing a consistent method.

static variable cbeg = Null_String, cmid = Null_String, cend = Null_String;
static variable Comment_Data = Assoc_Type[String_Type,",,"];

define set_comment ()
{
   variable smode, mode;
   (smode, mode) = what_mode ();
   variable s = strchop (Comment_Data[smode], ',', '\\');
   cbeg = s[0];
   cmid = s[1];
   cend = s[2];
}

Comment_Data ["html"] = "<!-- , -*- , --> ";
Comment_Data ["sgml"] = "<!-- , -*- , --> ";
Comment_Data ["C"] = "/* , * , */";
Comment_Data ["SLang"] = "% ,% ,";
Comment_Data ["TeX"] = "% ,% ,";
Comment_Data ["LaTeX"] = "% ,% ,";
Comment_Data ["SH"] = "# ,# ,";
Comment_Data ["matlab"] = "# ,# ,";
Comment_Data ["perl"] = "# ,# ,";
Comment_Data ["Fortran"] = "C ,C ,";
Comment_Data ["TPas"] = "{ ,* ,} ";

define comment_region ()
{
  set_comment ();
  push_spot ();
  narrow ();
  bob ();
  insert (cbeg);
  while (2 == down(2)) {
    go_up_1 ();
    bol ();
    insert (cmid);
  } 
  insert (cend);
  widen ();
  pop_spot ();
}

define uncomment_region ()
{
  variable len_cbeg, len_cmid, len_cend;
  set_comment ();
  len_cbeg = strlen (cbeg);
  len_cmid = strlen (cmid);
  len_cend = strlen (cend);
  push_spot ();
  narrow ();
  bob ();
  if (looking_at(cbeg)) deln(len_cbeg);
  while (down_1 ()) {
    bol ();
    if (looking_at(cmid)) deln(len_cmid);
    if (looking_at(cend)) deln(len_cend);
  }
  widen ();
  pop_spot ();
}

define comment_line ()
{
  set_comment ();
  push_spot ();
  bol ();
  insert (cbeg);
  eol ();
  if (Null_String != cend)
    insert (cend);
  pop_spot ();
}

define uncomment_line ()
{
  variable len_cbeg, len_cmid, len_cend;
  set_comment ();
  len_cbeg = strlen (cbeg);
  len_cmid = strlen (cmid);
  len_cend = strlen (cend);
  push_spot ();
  bol ();
  if (looking_at(cbeg)) deln(len_cbeg);
  eol ();
  left (len_cend);
  if (looking_at(cend)) deln(len_cend);
  pop_spot ();
}

%
% These are predefined bookmarks 0..9, a la Wordstar.
%

define ide_goto_mark_n (n)
{
   variable mrk = _Ide_Bookmarks[n];
   if (mrk == NULL)
     error ("Bookmark not set!");

   ide_set_bookmark ();
   sw2buf (mrk.buffer_name);
   goto_user_mark (mrk);
   message ("done.");
}

define ide_set_mark_n (n)		% ^K0..9
{
  _Ide_Bookmarks[n] = create_user_mark ();
  vmessage ("Bookmark %d set.", n);
}
   
define ide_save_buffer ()		% ^KS
{
   variable file = read_file_from_mini ("Save to file:");
   if (file == "")
     return;
   () = write_buffer (file);
}

define ide_better_help ()
{
  variable file = "ide";
  file = dircat (JED_ROOT, "lib/" + file + ".hlp");
  () = read_file (file);
  pop2buf (whatbuf ());
  most_mode ();
  call ("one_window");
  set_readonly (1);
}

static define close_file (clientdata)
{
   delbuf (whatbuf ());
}

% Menu Interface.  Use existing menu definitions in most cases, but 
% change definitions in others.  Make sure popups.sl is loaded.
menu_load_popups ("Global");

$1 = "Global.&File";
menu_delete_items ($1);
menu_append_item ($1, "&Open", "find_file");
menu_append_item ($1, "&Close", &close_file, NULL);
menu_append_item ($1, "&Save", "save_buffer");
menu_append_item ($1, "Save &As", "ide_save_buffer");
menu_append_item ($1, "Save &Buffers", "save_buffers");
menu_append_item ($1, "&Insert File", "ide_insert_file");
menu_append_popup ($1, "&Versions");
menu_append_separator ($1);
menu_append_item ($1, "Cance&l Operation", "kbd_quit");
menu_append_item ($1, "S&hell", "shell");
menu_append_item ($1, "E&xit", "exit_jed");

$1 = "Global.&File.&Versions";
menu_append_item ($1, "&Check In/Out", "rcs_check_in_and_out");
menu_append_item ($1, "RCS Read &Log", "rcs_read_log");
menu_append_item ($1, "Backups &On", "backups_on");
menu_append_item ($1, "Backups O&ff", "backups_off");

$1 = "Global.&Edit";
menu_delete_items ($1);
menu_append_item ($1, "&Begin Region/Rect", "ide_begin_block");
menu_append_item ($1, "&Cut", "ide_delete_block");
menu_append_item ($1, "C&opy", "ide_clear_block");
menu_append_item ($1, "&Paste", "ide_copy_block");
menu_append_separator ($1);
menu_append_popup ($1, "&Rectangles");
menu_append_popup ($1, "Bloc&ks");
menu_append_popup ($1, "&Advanced");
menu_append_separator ($1);
menu_append_item ($1, "Re&format", "format_paragraph");
menu_append_item ($1, "&Undo", "undo");

$1 = "Global.&Edit.&Advanced";
menu_append_item ($1, "&Compose Character", "ide_insert_any_char");
menu_append_item ($1, "S&pecial Character", "digraph_cmd"); % digraph.sl req.
menu_append_item ($1, "Toggle &Abbrev Mode", "abbrev_mode");
if (is_defined ("toggle_auto_ispell"))
  menu_append_item ($1, "Toggle Auto &Ispell", "toggle_auto_ispell");
menu_append_item ($1, "Co&mpletion", "dabbrev");
menu_append_item ($1, "C&enter Line", "center_line");
menu_append_separator ($1);
menu_append_item ($1, "&Start Macro", "begin_macro");
menu_append_item ($1, "S&top Macro", "end_macro");
menu_append_item ($1, "&Replay Last Macro", "execute_macro");

$1 = "Global.&Edit.&Rectangles";
menu_append_item ($1, "&Cut Rectangle", "kill_rect");
menu_append_item ($1, "C&opy Rectangle", "copy_rect");
menu_append_item ($1, "&Paste Rectangle", "insert_rect");
menu_append_item ($1, "Op&en Rectangle", "open_rect");
menu_append_item ($1, "&Blank Rectangle", "blank_rect");

$1 = "Global.&Edit.Bloc&ks";
menu_append_item ($1, "&Write to File", "write_region");
menu_append_item ($1, "&Filter", "ide_filter_region");
menu_append_item ($1, "&Sort", "sort");
menu_append_item ($1, "&Upper Case", "ide_uppercase_region");
menu_append_item ($1, "&Lower Case", "ide_lowercase_region");
menu_append_item ($1, "Copy To &Register", "reg_copy_to_register");
menu_append_item ($1, "&Paste From Register", "reg_insert_register");
menu_append_item ($1, "&Comment", "comment_region");
menu_append_item ($1, "U&ncomment", "uncomment_region");

$1 = "Global.&Search";
menu_append_item ($1, "Search &Forward", "ide_search_forward");
menu_append_item ($1, "Repeat &Last Search", "ide_repeat_search");
menu_append_item ($1, "&Replace", "ide_replace_cmd");
menu_append_item ($1, "Search &Match", "goto_match");

$1 = "Global.&Buffers";
menu_append_separator ($1);
menu_append_item ($1, "C&ompile", "compile");
menu_append_item ($1, "&Next Error", "compile_parse_errors");
menu_append_item ($1, "&Previous Error", "compile_previous_error");
if (is_defined ("gdb_mode"))
  menu_append_item ($1, "Debug with &gdb", "gdb_mode");
 

$1 = "Global.&Help";
menu_append_separator ($1);
menu_append_item ($1, "Describe ID&E Mode", "ide_better_help");

% --- End of file ide.sl ---
