HEX
Server: Apache
System: Linux pdx1-shared-a1-38 6.6.104-grsec-jammy+ #3 SMP Tue Sep 16 00:28:11 UTC 2025 x86_64
User: mmickelson (3396398)
PHP: 8.1.31
Disabled: NONE
Upload Files
File: //usr/share/jed/lib/folding.sl
% -*- mode: slang; mode: fold -*-

ifnot (is_defined ("Fold_Bob_Eob_Error_Action")) %{{{
{
%!%+
%\variable{Fold_Bob_Eob_Error_Action}
%\synopsis{Fold_Bob_Eob_Error_Action}
%\usage{Integer Fold_Bob_Eob_Error_Action = 1;}
%\description
% This value of this variable determines the what will happen upon
% reaching the boundary of the current fold via the up/down keys.
% If the value is 0, an error will be generated; if the value is 1,
% the fold will be exited; otherwise, the next/previous fold will be
% entered.
%!%-
variable Fold_Bob_Eob_Error_Action = 1;
}

%}}}

%{{{ Associating fold marks with modes

%mode_set_mode_info ("score", "fold_info", "%{{{\r%}}}\r\r");

define fold_get_marks_for_mode () %{{{
{
   variable mode, fold_marks;

   fold_marks = mode_get_mode_info ("fold_info");

   if (fold_marks == NULL)
     return ("{{{", "}}}", "", "");

   % push the marks on stack
   foreach (strchop (fold_marks, '\r', 0))
     ;
}

%}}}

define fold_get_marks () %{{{
{
#ifdef HAS_BLOCAL_VAR
   ERROR_BLOCK
     {
	_clear_error ();
	error ("Folding mode not enabled for buffer.");
     }
   get_blocal_var ("fold_start");
   get_blocal_var ("fold_end");
   get_blocal_var ("fold_end_of_start");
   get_blocal_var ("fold_end_of_end");
#else
   fold_get_marks_for_mode ();
#endif
}

%}}}

%}}}

%{{{ Basic functions:

private define fold_is_marker_line (start, end_of_start) %{{{
{
   bol_skip_white ();
   if (looking_at (start))
     {
	return 1;
     }
   eol ();
   ifnot (bfind (start))
     {
	return 0;
     }

   go_right (strlen (__tmp(start)));
%   skip_white ();
%   end_of_start = strtrim (__tmp(end_of_start));
%
%   ifnot (looking_at (end_of_start))
%     return 0;
   () = ffind (end_of_start);

   go_right (strlen (end_of_start));
   skip_white ();
   eolp ();
}

%}}}
private define fold_find_marker_line (start, end_of_start) %{{{
{
   bol ();
   while (fsearch (start))
     {
	if (fold_is_marker_line (start, end_of_start))
	  return 1;
	eol ();
     }
   return 0;
}

%}}}
private define fold_find_marker_line_reverse (start, end_of_start, hidden_check) %{{{
{
   eol ();
   while (bsearch (start))
     {
	if (fold_is_marker_line (start, end_of_start))
	  {
	     ifnot (hidden_check and is_line_hidden ())
	       return 1;
	  }
	bol ();
     }
   return 0;
}
%}}}
private define fold_this_fold (start, end, end_of_start, end_of_end,
		       start_level, fold_level) %{{{
{
   variable level = start_level;

   while (down_1 ())
     {
   	set_line_hidden (level >= fold_level);

	if (fold_is_marker_line (start, end_of_start)) level++;
	else if (fold_is_marker_line (end, end_of_end))
	  {
	     if (level == start_level) break;
	     level--;
	  }
     }
}

%}}}
define fold_open_buffer () %{{{
{
   push_spot ();
   widen_buffer ();
   mark_buffer ();
   set_region_hidden (0);
   pop_spot ();
}

%}}}

define fold_whole_buffer () %{{{
{
   variable start, end, end_of_start, end_of_end;
   variable level, fold_level;

   flush ("folding buffer...");
   ERROR_BLOCK
     {
	pop_spot ();
     }
   push_spot ();

   fold_open_buffer ();

   bob ();
   (start, end, end_of_start, end_of_end) = fold_get_marks ();

   fold_level = prefix_argument (-1);
   if (fold_level <= 0) fold_level = 1;

   while (fold_find_marker_line (start, end_of_start))
     {
	fold_this_fold (start, end, end_of_start, end_of_end,
			1, fold_level);
	ifnot (down_1 ())
	  break;
     }

   pop_spot ();
   if (is_line_hidden ())
     {
	skip_hidden_lines_backward (1);
	bol ();
     }
   flush ("folding buffer...done");
}

%}}}
private define fold_is_fold (start, end_of_start) %{{{
{
   push_spot ();
   EXIT_BLOCK
     {
	pop_spot ();
     }

   ifnot (fold_is_marker_line (start, end_of_start))
     return 0;

   % Check to make sure this is not the top of the current fold by making
   % sure that the next line is hidden.
   ifnot (down_1 ()) return 0;
   return is_line_hidden ();
}

%}}}
define fold_open_fold () %{{{
{
   variable start, end, end_of_start, end_of_end;

   (start, end, end_of_start, end_of_end) = fold_get_marks ();
   push_spot ();
   if (is_line_hidden ())
     skip_hidden_lines_backward (1);
   if (fold_is_fold (start, end_of_start))
     {
	fold_this_fold (start, end, end_of_start, end_of_end, 0, 1);
     }
   pop_spot ();
}

%}}}
define fold_enter_fold () %{{{
{
   variable start, end, end_of_start, end_of_end;
   variable h;

   (start, end, end_of_start, end_of_end) = fold_get_marks ();

   push_spot ();

   while (fold_find_marker_line_reverse (start, end_of_start, 1))
     {
	push_mark ();
	if (fold_is_fold (start, end_of_start))
	  {
	     fold_this_fold (start, end, end_of_start, end_of_end, 0, 1);
	     narrow ();
	     bob ();
	  }
	else
	  {
	     pop_mark_1 ();
	     break;
	  }
	goto_spot ();
	ifnot (is_line_hidden ())
	  break;
     }

   pop_spot ();
}

%}}}

define fold_close_this_fold () %{{{
{
   variable start, end, end_of_start, end_of_end;

   (start, end, end_of_start, end_of_end) = fold_get_marks ();

   ifnot (fold_find_marker_line (start, end_of_start))
     error ("Unable to find fold-start");

   fold_this_fold (start, end, end_of_start, end_of_end, 1, 1);
   skip_hidden_lines_backward (1);
}
%}}}

define fold_close_fold () %{{{
{
   variable start, end, end_of_start, end_of_end;
   variable beg_mark, end_mark;
   variable not_in_a_fold = "Not in a fold.";
   variable end_line;

   (start, end, end_of_start, end_of_end) = fold_get_marks ();

   push_spot();

   if (fold_is_marker_line (start, end_of_start) && down_1())
     {
        is_line_hidden();
        go_up_1();
        ifnot (())
          {
             fold_this_fold (start, end, end_of_start, end_of_end, 1, 1);
             pop_spot();
             return;
          }
     }

   beg_mark = create_user_mark ();
   end_mark = create_user_mark ();

   forever
     {
        if (up_1() && fold_find_marker_line_reverse (end, end_of_end, 0))
          {
             end_line = what_line ();
             move_user_mark (end_mark);
          }
        else
          end_line= 0;

        goto_user_mark (beg_mark);

        if (up_1() && fold_find_marker_line_reverse (start, end_of_start, 0))
          {
             move_user_mark (beg_mark);
             if ( what_line () > end_line) break;
          }
        else
          {
             pop_spot ();
             error (not_in_a_fold);
          }
        goto_user_mark (end_mark);
     }

   fold_this_fold (start, end, end_of_start, end_of_end, 1, 1);
   pop_spot();
   goto_user_mark (beg_mark);
   bol();
}
%}}}

private define fold_exit_fold_internal () %{{{
{
   ifnot (count_narrows ())
     {
	error ("You are not in a fold.");
	return;
     }

   bob ();
   widen ();

   fold_close_this_fold ();
}

%}}}

define fold_exit_fold () %{{{
{
   fold_exit_fold_internal ();
   recenter (window_info ('r') / 2);
}

%}}}

define fold_fold_region () %{{{
{
   variable start, end, end_of_start, end_of_end;

   check_region (0);
   (start, end, end_of_start, end_of_end) = fold_get_marks ();

   % We have a canonical region with point at end.  See if this line
   % is the start of a fold.  If so, extend it to cover all of fold.

   if (fold_is_fold (start, end_of_start))
     {
	skip_hidden_lines_forward (1);
	ifnot (is_line_hidden ())
	  go_up_1 ();
     }

   narrow ();
   eob ();
   newline ();
   insert (end);
   insert (end_of_end);
   newline ();

   bob ();
   % Now look at position of beginning of region.  If it does not occur on
   % a blank line, put fold marks at end of line.
   skip_white ();
   if (eolp ())
     {
	bol ();
	insert (start);
	push_spot ();
	insert (end_of_start);
	newline ();
     }
   else
     {
	eol ();
	trim ();
	insert_single_space ();
	insert (start);
	insert (end_of_start);
	bol ();
	push_spot ();
     }

   fold_exit_fold_internal ();
   pop_spot ();
}

%}}}

%}}}

define fold_parse_errors () %{{{
{
   variable folded;

   % compile_parse_errors will widen buffer the buffer.  As a result, when it
   % returns, the buffer will be unfolded but some lines may be hidden.  Simply
   % unhide all lines.  Also take care to reenter a fold only if buffer is not
   % folded.
   compile_parse_errors ();

   push_spot ();
   eob ();
   skip_hidden_lines_backward (0);
   folded = is_line_hidden ();
   pop_spot ();

   if (folded)
     {
	push_spot ();
	fold_open_buffer ();
	fold_whole_buffer ();
	pop_spot ();
	if (is_line_hidden ()) fold_enter_fold ();
     }
}

%}}}

#ifdef HAS_BLOCAL_VAR
define fold_goto_bookmark_hook (mrk) %{{{
{
   variable folded;

   while (not (is_user_mark_in_narrow (mrk)))
     fold_exit_fold_internal ();

   goto_user_mark (mrk);
   fold_enter_fold ();
}

%}}}
#endif

define fold_bob_eob_error_hook (f) %{{{
{
   variable str = "Top Of Buffer.";
   variable start, end, end_of_start, end_of_end;

   if (f > 0) str = "End Of Buffer.";

   ifnot (Fold_Bob_Eob_Error_Action)
     error (str);

   ifnot (count_narrows () and (abs(f) == 1)) error (str);

   fold_exit_fold ();

   % The rest of this function is should be made optional, e.g.,
   % if (Optional_Flag) return;

   if (Fold_Bob_Eob_Error_Action == 1)
     return;

   bol ();
   if (f > 0)
     {
	skip_hidden_lines_forward (1);
	skip_chars (" \t\n");
     }
   else
     {
	bskip_chars (" \t\n");
	skip_hidden_lines_backward (1);
     }

   (start, end, end_of_start, end_of_end) = fold_get_marks ();

   if (fold_is_fold (start, end_of_start))
     fold_enter_fold ();
}

%}}}

%{{{ mouse interface
$1 = "mouse_goto_position";
$2 = "mouse";
ifnot (is_defined ($1)) autoload ($1, $2);

define fold_mouse_2click (line, col, but, shift) %{{{
{
   variable start, end, end_of_start, end_of_end;
   if (but == 1)
     {
	(start, end, end_of_start, end_of_end) = fold_get_marks ();
	mouse_goto_position (col, line);

	ERROR_BLOCK
	  {
	     _clear_error ();
	  }
	if (fold_is_fold (start, end_of_start))
	  fold_enter_fold ();
	else
	  fold_exit_fold ();

	return 1;
     }

   return -1;
}

%}}}

%}}}

define fold_goto_line ()
{
   variable n = read_mini ("Goto Line:", "", "");
   ifnot (strlen (n))
     return;
   n = integer (n);
   fold_open_buffer ();
   goto_line (n);
}

%{{{ Interactive searching functions

define fold_search_line_ok () %{{{
{
   not (is_line_hidden ());
}

%}}}

$1 = "search_generic_search";
$2 = "search";
ifnot (is_defined ($1)) autoload ($1, $2);

define fold_search_backward () %{{{
{
   search_generic_search ("Fold search backward:", -1, &fold_search_line_ok);
}

%}}}

define fold_search_forward () %{{{
{
   search_generic_search ("Fold search forward:", 1, &fold_search_line_ok);
}

%}}}

%}}}

define folding_mode () %{{{
{
   variable s, s1, e, e1;

   if (Fold_Mode_Ok == 0)
     {
	if (1 != get_yes_no ("Folding mode not enabled.  Enable it"))
	  return;
	Fold_Mode_Ok = 1;
     }

#ifdef HAS_BLOCAL_VAR
   (s, e, s1, e1) = fold_get_marks_for_mode ();

   define_blocal_var ("fold_start", s);
   define_blocal_var ("fold_end_of_start", s1);
   define_blocal_var ("fold_end", e);
   define_blocal_var ("fold_end_of_end", e1);
   define_blocal_var ("bookmark_narrow_hook", ".fold_goto_bookmark_hook");
#endif

   local_setkey_reserved ("fold_whole_buffer",		"^W");
   local_setkey_reserved ("fold_enter_fold",		">");
   local_setkey_reserved ("fold_exit_fold",		"<");
   local_setkey_reserved ("fold_open_buffer",		"^O");
   local_setkey_reserved ("fold_open_fold",		"^S");
   local_setkey_reserved ("fold_close_fold",		"^X");
   local_setkey_reserved ("fold_fold_region",		"^F");
   local_setkey_reserved ("fold_search_forward",	"f");
   local_setkey_reserved ("fold_search_backward",	"b");

   set_buffer_hook ("bob_eob_error_hook", "fold_bob_eob_error_hook");
#iffalse
   set_buffer_hook ("mouse_2click", "fold_mouse_2click");
#endif
   loop (which_key ("compile_parse_errors"))
     {
	local_setkey ("fold_parse_errors", exch ());
     }

   fold_whole_buffer ();

   run_mode_hooks ("fold_mode_hook");
}
%}}}

define c_fold_buffer () %{{{
{
   bob ();
   ifnot (ffind ("mode: fold"))
     {
	insert ("/* -*- mode: C; mode: fold; -*- */\n");
     }
   folding_mode ();
   fold_open_buffer ();

   while (bol_fsearch ("{"))
     {
	eol ();
	push_mark ();

	go_up_1 ();		       %  at eol
	ifnot (re_bsearch ("^[a-z_A-Z]"))
	  {
	     pop_mark_1 ();
	     continue;
	  }

	if (ffind ("{{{"))
	  {
	     pop_mark_1 ();
	     continue;
	  }

	exchange_point_and_mark ();

	ifnot (bol_fsearch ("}"))
	  {
	     pop_mark_1 ();
	     error ("Matching } at bol not found.");
	  }
	go_down_1 ();
	trim ();
	ifnot (eolp ())
	  {
	     newline ();
	     go_up_1 ();
	  }
	push_spot ();
	fold_fold_region ();
	pop_spot ();
     }

   fold_whole_buffer ();
   bob ();
}

%}}}

% Fold menu support

private define fold_menu_callback (m)
{
#ifdef HAS_BLOCAL_VAR
   ifnot (blocal_var_exists ("fold_start"))
     {
	menu_append_item (m, "Enable &Folding", "folding_mode");
	return;
     }
#endif
   menu_append_item (m, "&Fold Buffer", "fold_whole_buffer");
   menu_append_item (m, "&Unfold Buffer", "fold_open_buffer");
   menu_append_item (m, "&Enter Fold", "fold_enter_fold");
   menu_append_item (m, "E&xit Fold", "fold_exit_fold");
   menu_append_item (m, "&Open Fold", "fold_open_fold");
   menu_append_item (m, "&Close Fold", "fold_close_fold");
   menu_append_item (m, "Fold &Region", "fold_fold_region");
   menu_append_item (m, "&Search Forward", "fold_search_forward");
   menu_append_item (m, "S&earch Backward", "fold_search_backward");
}

private define install_fold_menus ()
{
   menu_delete_item ("Global.&Buffers.Enable &Folding");
   menu_append_popup ("Global.&Buffers", "&Folding");
   menu_set_select_popup_callback ("Global.&Buffers.&Folding", &fold_menu_callback);
}

if (Menu_Popups_Loaded)
  install_fold_menus ();
else
  add_to_hook ("load_popup_hooks", &install_fold_menus);