jed-users mailing list

[2006 Date Index] [2006 Thread Index] [Other years]
[Thread Prev] [Thread Next]      [Date Prev] [Date Next]

Looking for C/C++ (and S-Lang) programmers for testing


Akin to Guenter's Python posting, I'm looking for input, and for testers and
of the modified c-mode. 

For some background: I've recently started working with C/C++ on a
particular project (www.openfoam.org) and found that the JED c-mode kept
getting in the way of the coding standards for the project. The style is a
slight variation of BSD style, which looked horrible with the default
parenthesis indentation semantics. In adjusting the c-mode code, I also
streamlined it a bit and add comments (so I could understand what it is
doing).

Here is a summary of the changes, followed by the cmode.sl itself.
I believe that the changes are an general improvement, and shouldn't break
any existing styles, but of course this must be (critically) tested on real
code.  Please let me know what works or doesn't work so that it can get
fixed before 'proper' submittal.

I've added as text below, to avoid mangled attachments.

Thanks,
/mark


// The major changes to -*- c-mode -*-

// parentheses alignment
// - ignore eol trailing space after '('

// parentheses alignment
// - align ')' under its matching '('

{
    BEFORE:
    function(
             arg1,
             ...
             argN
             );

    if (
        ...
        ) {
    }

    AFTER:
    function(
             arg1,
             ...
             argN
            );

    if (
        ...
       ) {
    }

}

// parentheses alignment - solitary starting '('
// - indent parameter arguments with C_INDENT
// - no indent for solitary '(' and ')'
{
    BEFORE:
    function
        (
         arg1,
         ...
         argN
         );

    AFTER:
    function
    (
        arg1,
        ...
        argN
    );
}


// Outdent operators within (...) groups starting with a solitary '('
// - only active for C_IDENT >= 3 and for isolated operators
{
    BEFORE:
    while
        (
         expr1
         + expr2
         == expr3
         ) ...;

    AFTER:
    while
    (
        expr1
      + expr2
     == expr3
    ) ...;

    UNCHANGED:
    while
    (
        expr1
        +expr2
        ==expr3
    ) ...;

    while (
           expr1
           + expr2
           == expr3
          ) ...;

}

// line_terminated(): added special treatment for lines ending in ')'
// and starting with any type of operator
// - helps prevent staircase indentation
{
    BEFORE:
    a = 1
        * (2 + 3)
            * (4 + 5)
                / 6;

    cout<< something()
        << obj.member()
            << obj.member()
                << endl;

    AFTER:
    a = 1
        * (2 + 3)
        * (4 + 5)
        / 6;

    cout<< something()
        << obj.member()
        << obj.member()
        << endl;
}


// Check for ':' on the line before checking for "case" .. "public".
//  - seems to help with some C++ classes

-------------

% New C-mode indentation routines
% 2006-09-13
%
%require ("profile");
%profile_calibrate ();
%profile_begin ();

autoload ("c_make_comment", "cmisc");
autoload ("c_format_paragraph", "cmisc");
autoload ("c_paragraph_sep", "cmisc");
% autoload ("c_comment_region", "cmisc");
autoload ("c_top_of_function", "cmisc");
autoload ("c_end_of_function", "cmisc");
autoload ("c_mark_function", "cmisc");
autoload ("c_indent_buffer", "krconv");

%!%+
%\variable{C_Autoinsert_CPP_Comments}
%\synopsis{Control insertion of C++ comments}
%\description
% In c-mode, if a line starts with //, then pressing return will cause the
% next line to also start with //.  This feature is useful for writing
% multiple comment lines using C++ style comments.
%\seealso{c_mode}
%!%-
custom_variable ("C_Autoinsert_CPP_Comments", 1);
custom_variable ("C_Switch_Offset", 0);
%\variable{C_Namespace_Offset}
%\synopsis{C_Namespace_Offset}
%\description
% Integer C_Namespace_Offset = 3;
% This variable may be changed to adjust the indentation of members
% inside of a class declaration block.
%\seealso{c_mode}
%\seealso{C_BRA_NEWLINE, C_BRACE, C_Class_Offset, C_INDENT,
C_Namespace_Offset}
%!%-
custom_variable ("C_Namespace_Offset", 3);

%!%+
%\variable{C_Class_Offset}
%\synopsis{C_Class_Offset}
%\description
% Integer C_Class_Offset = 3;
% This variable may be changed to adjust the indentation of members
% inside of a class declaration block.
%\seealso{c_mode}
%\seealso{C_BRA_NEWLINE, C_BRACE, C_INDENT, C_Namespace_Offset}
%!%-
custom_variable ("C_Class_Offset", 3);

%!%+
%\variable{C_Param_Offset_Max}
%\synopsis{Control indentation of continued parameter list}
%\usage{Integer C_Param_Offset_Max = -1}
%\description
% This variable may be changed to adjust the indentation of parameters
% in a funcion call that extends over multiple lines.
%
% If the value is less than 0, the feature is off, otherwise
% it holds the max number of spaces to indent the parameters on
% the continuation line(s).
%\seealso{c_mode}
%\seealso{C_BRA_NEWLINE, C_BRACE, C_INDENT}
%!%-
custom_variable ("C_Param_Offset_Max", -1);

define cmode_is_slang_mode ()
{
   variable is_slang;
   (, is_slang) = what_mode ();
   is_slang & 8;
}

private define bskip_all_whitespace ()
{
   bskip_chars (" \f\t\n");
}

private define skip_all_whitespace ()
{
   skip_chars (" \f\t\n");
}

private define skip_identifier ()
{
   skip_chars ("a-zA-Z0-9_$");
}

private define bskip_identifier ()
{
   bskip_chars ("a-zA-Z0-9_$");
}

private define bextract_identifier ()
{
   push_mark ();
   bskip_identifier ();
   return bufsubstr ();
}

private define skip_comment ()
{
   variable is_slang = cmode_is_slang_mode ();

   forever
     {
	skip_all_whitespace ();
	if (eobp ())
	  return;

	if (is_slang)
	  {
	     !if (looking_at_char ('%'))
	       return;

	     eol ();
	     continue;
	  }

	if (looking_at ("/*"))
	  {
	     !if (fsearch ("*/"))
	       return;
	     go_right(2);
	     continue;
	  }

	if (looking_at ("//"))
	  {
	     eol ();
	     continue;
	  }

	return;
     }
}

private define extract_identifier ()
{
   push_mark ();
   skip_identifier ();
   return bufsubstr ();
}

% search within non-comment or non-string regions
private define c_search (fun, str)
{
   while ((@fun)(str))
     {
	!if (parse_to_point ())
	  {
	     return 1;
	  }

	% re-try
	go_right_1 ();
     }
   return 0;
}

private define c_fsearch (str)
{
   return c_search (&fsearch, str);
}

private define c_bol_fsearch (str)
{
   return c_search (&bol_fsearch, str);
}

private define c_re_fsearch (str)
{
   return c_search (&re_fsearch, str);
}

private define slmode_find_effective_eol ()
{
   bol ();
   while (ffind_char ('%'))
     {
	go_right_1 ();
	if (parse_to_point () == -2)
	  {
	     return;
	  }
     }
   eol ();
}

private define slmode_bskip_comment (is_normal_statement)
{
   forever
     {
	while (parse_to_point () == -2)
	  {
	     () = bfind_char ('%');
	  }

	bskip_white ();

	push_mark ();
	bol ();
	pop_mark (not(looking_at_char ('#')));

	!if (bolp ()) return;
	!if (left (1)) return;
	slmode_find_effective_eol ();
     }
}

% backtrack across all backslash continued lines
private define bskip_continued_lines ()
{
   while (up_1 ())
     {
	!if (blooking_at ("\\"))
	  {
	     go_down_1 ();
	     break;
	  }
     }
}

% This function also skips preprocessor lines
private define bskip_comment (is_normal_statement)
{
   if (cmode_is_slang_mode ())
     return slmode_bskip_comment (is_normal_statement);

   forever
     {
	bskip_all_whitespace ();
	if (bobp ())
	  return;

	if (is_normal_statement)
	  {
	     push_mark ();
	     bskip_continued_lines ();
	     bol_skip_white ();
	     if (looking_at_char ('#'))
	       {
		  pop_mark_0 ();
		  continue;
	       }
	     pop_mark_1 ();
	  }

	!if (blooking_at ("*/"))
	  {
	     push_mark ();
	     variable ptp = -2;
	     while (andelse {ptp == -2} {bfind ("//")} )
	       ptp = parse_to_point ();

	     !if (ptp)
	       {
		  % Not in a comment or string
		  pop_mark_0 ();
		  continue;
	       }

	     bol ();
	     !if (bobp ())
	       {
		  if (is_normal_statement and looking_at_char ('#'))
		    {
		       pop_mark_0 ();
		       continue;
		    }
	       }
	     pop_mark_1 ();
	     break;
	  }
	!if (bsearch ("/*")) break;
     }
}

private define colon_statement ()
{
   push_spot();
   ffind_char (':');	%  leave on stack
   pop_spot();

   !if (()) return 0;   %  take argument from stack

   variable cse = CASE_SEARCH;
   CASE_SEARCH = 1;

   EXIT_BLOCK
     {
	CASE_SEARCH = cse;
     }

   foreach (["case", "default", "private", "protected", "public"])
     {
	variable token = ();

	if (looking_at(token))
	  {
	     push_spot ();
	     go_right(strlen(token));
	     _get_point ();
	     skip_chars ("\t :({");
	     (_get_point () - ()) or eolp();   %  leave on stack
	     pop_spot ();
	     if (())    %  take argument from stack
	       return 1;
	  }
     }

   return 0;
}

% Force a reindent if the line does not contain tabs followed by spaces.
private define c_indent_to (n)
{
   push_spot_bol ();
   skip_chars ("\t");
   skip_chars (" ");

   if ((what_column != n)
       or (_get_point () != (skip_white (), _get_point ())))
     {
	bol_trim ();
	n--;
	whitespace (n);
     }
   pop_spot ();
}

private define c_indent_preprocess_line ()
{
   variable col;

   push_spot ();
   bol_trim ();
   !if (up_1 ())
     {
	pop_spot ();
	return;
     }

   !if (bol_bsearch_char ('#'))
     {
	pop_spot ();
	return;
     }

   go_right_1 ();
   skip_white ();
   col = what_column ();

   if (looking_at ("if"))
     col += C_Preprocess_Indent;
   else if (looking_at ("el"))
     col += C_Preprocess_Indent;

   % what does all this do - looking at 'endif' perhaps ?
   pop_spot ();
   go_right_1 ();
   skip_white ();

   !if (looking_at ("error"))
     {
	if (looking_at_char ('e'))
	  col -= C_Preprocess_Indent;
     }

   if (what_column () == col)
     return;
   bskip_white ();
   trim ();
   whitespace (col - 2);
}

private define c_indent_continued_comment (col)
{
   col++;			       %  add 1 to align with * in /*
   c_indent_to (col);
   push_spot ();
   bol_skip_white ();

   if (looking_at_char ('*') or not (eolp ()))
     {
	pop_spot ();
     }
   else
     {
	insert ("* ");
	pop_spot ();
	if (what_column () <= col)
	  {
	     goto_column (col + 2);
	  }
     }
}

private define c_mode_if_bol_skip_white ()
{
   push_mark ();
   bskip_white ();
   1;
   if (bolp ())
     {
	pop ();
	skip_white ();
	0;
     }
   pop_mark (());		       %  take argument from stack
}

%
% detect 1 or 2 character tokens at the beginning of the line
% that would appear to be operators.
% The parameter 'isolated' controls is space is required after the token.
%
% usage 1 (isolated == 0):
% improved indentation for continuations ending with ')'
% eg:
%    a = 2
%        * (3 + 4)
%        * (5 + 6);
% eg, a typical C++ construct:
%    cout<< something()
%        << obj.member()
%        << obj.member()
%        << endl;
%
% usage 2 (isolated == 1):
% nice alignment on (space-delimited) operators within parentheses
% Note: false positive on C/C++ comments within parentheses!
% eg,
%    while
%    (
%        some_expression
%      + other_expression
%     == something
%    ) ...
%
%
% return the outdent value (0, -2 or -3)
%
private define operator_outdent (isolated)
{
   variable len;

   push_spot();
   bol_skip_white();

   EXIT_BLOCK
     {
	pop_spot ();
     }

   len = _get_point ();
   _get_point ();
   if (cmode_is_slang_mode ())
     skip_chars("-+*/&<=>|");	%  (avoid '!if' strangeness)
   else
     skip_chars("-+*/!&<=>|");	%  assignment, comparison, logicals

   len -= _get_point();
   len--;

   if ((len == -2) or (len == -3))
     {
	!if (isolated)        % don't require an isolated operator
	  return len;

	_get_point ();
	skip_white ();
	if ((_get_point () - ()) or eolp())
	  {
	     return len;
	  }
     }

   return 0;
}

%
% various combinations of endings that indicate that we can
% start a new (non-continued) statement
%
private define line_terminated ()
{
#iftrue
   if ( orelse {bobp()}
	   { blooking_at (";") }
	   { blooking_at (":") }
	   { blooking_at ("{") }
	   { blooking_at ("}") }
	   { blooking_at ("),") }
	   { blooking_at ("},") }
      )
     {
	return 1;
     }
   else if (blooking_at (")"))
     {
	return operator_outdent(0);
     }
   else
     {
	return 0;
     }
#else
   % the same thing, but without blooking_at()
   % perhaps more efficient, but also messier looking
   variable ch;

   if (bobp())
     return 1;

   push_spot ();

   EXIT_BLOCK
     {
	pop_spot ();
     }

   !if (left(1))
     return 0;

   ch = what_char();
   switch (ch)
     { case ')' : return operator_outdent(0); }
     { case ',' :	% '),' or '},'
	if (left(1))
	  {
	     ch = what_char();
	     if (is_substr(")}", char(ch))) return 1;
	  }
     }
     { (is_substr(":;{}", char(ch))) : return 1; }

   return 0;
#endif
}

#iftrue
% Return true if the spot is inside of a class definition
% Takes the opening brace of the enclosing block as an
% argument.
private define inside_class_or_namespace (brace_mark, name)
{
   push_spot ();

   EXIT_BLOCK
     {
	pop_spot ();
     }

   goto_user_mark (brace_mark);

   % Assume that class/namespace is at the beginning of a line.
   % We may want to change this assumption later.
   variable re = sprintf ("\\c\\<%s\\>", name);
   while (re_bsearch (re))
     {
	if (name == "class")
	  {
	     bskip_chars (" \t<");	       %  allow: template <class...
	     if (blooking_at ("template"))
	       go_left (8);
	  }

	bskip_white ();
	if (bolp () and not(parse_to_point ()))
	  {
	     !if (c_fsearch ("{"))
	       break;

	     return brace_mark == create_user_mark ();
	  }

	!if (left(1))
	  break;
     }

   return 0;
}
#endif

% overview of indentation tracking variables
%
% this_char:
%   - 1st character at the begin of the current line
% match_char:
%   - start character of an enclosing '([{}])' construct, or where we gave
up
% match_indent:
%   - indentation of the match_char (possibly our reference point)
% match_line:
%   - where the match occurred
% prep_indent:
%   - extra indentation for multi-line preprocessor statements
% is_normal_statement:
%   - 1: indenting normal statement;
%   - 0: indenting preprocessor statements (use prep_indent)
% prep_line:

% is_continuation = 0;

define c_indent_line ()
{
   variable val, col;
   variable extra_indent = 0, prep_indent = 0;
   variable is_continuation = 0, is_normal_statement = 1;
   variable prep_line = 0;
   variable match_char, match_indent, match_line, this_char;
   variable match_mark;

   push_spot ();
   bol_skip_white ();
   this_char = what_char ();

   if (-2 == parse_to_point ())
     {
	% In a comment.  Indent to level of matching /* string
	() = bsearch ("/*");
	col = what_column ();
	pop_spot ();
	if (this_char == '\\')		% could be "\*" ... "*/" corners
	  col--;
	c_indent_continued_comment (col);
	c_mode_if_bol_skip_white ();
	return;
     }

   EXIT_BLOCK
     {
	bol_trim ();
	pop_spot ();
     }

   if (this_char == '#')
     {
	c_indent_preprocess_line ();
	return;
     }

   push_spot ();
   if (up_1 ())
     {
	% strange - here we check against "\\" but don't bother
	%   in bskip_continued_lines
	if (blooking_at ("\\") and not (blooking_at ("\\\\")))
	  {
	     bskip_continued_lines ();
	     bol ();
	     !if (looking_at_char ('#'))
	       {
		  pop_spot ();
		  return;
	       }
	     % special indentation for preprocessor statments
	     is_normal_statement = 0;
	     prep_indent = C_INDENT;
	     prep_line = what_line ();
	  }
     }
   pop_spot ();

   EXIT_BLOCK
     {
	c_mode_if_bol_skip_white ();
     }

   if (colon_statement())
     {
	extra_indent -= C_INDENT;
	extra_indent += C_Colon_Offset;
	bol ();
     }
   else
     {
	forever
	  {
	     bskip_comment (is_normal_statement);
	     if (eolp() and blooking_at ("\\"))
	       {
		  go_left_1 ();
		  continue;
	       }

	     !if (line_terminated())
	       {
		  if (is_normal_statement or is_continuation)
		    {
		       extra_indent += C_CONTINUED_OFFSET;
		    }
		  else
		    {
		       push_spot_bol ();
		       skip_white ();   % <- is this really needed?
		       !if (looking_at_char ('#'))
			 extra_indent += C_CONTINUED_OFFSET;
		       pop_spot ();
		    }

		  is_continuation++;
	       }

	     !if (blooking_at (")")) break;
	     push_mark ();
	     go_left_1 ();
	     if (1 != find_matching_delimiter (')'))
	       {
		  pop_mark_1 ();
		  break;
	       }
	     bskip_comment (is_normal_statement);
	     push_spot ();
	     if ((1 == find_matching_delimiter (')')), pop_spot ())
	       {
		  pop_mark_1 ();
		  break;
	       }

	     pop_mark_0 ();
	     bol ();

	     !if (is_normal_statement)
	       {
		  if (looking_at_char ('#'))
		    break;
	       }
	  }
     }

   if (not(is_normal_statement) and looking_at_char ('#'))
     val = 0;
   else
     val = find_matching_delimiter (')');

   match_mark = create_user_mark ();
   match_char = what_char ();
   match_line = what_line ();
   col = what_column ();

   if (val == 1)
     {                                  %  within (...) grouping
	extra_indent = 0;	        %  match found
	!if (this_char == ')')
	  {
	     go_right_1 ();
	     skip_white ();
	     !if (eolp())      % ignore trailing whitespace
	       col = what_column ();
	  }
     }
   else if ((val < 0) and looking_at ("/*"))
     {
	val = -2;
     }

   bol_skip_white ();
   match_indent = what_column ();
   if (what_line () < prep_line)
     {
	match_char = 0;
     }

   pop_spot ();

   variable cppComment = "// ";

#iftrue
   % Added 04/06/98 MDJ to facilitate C++ style comments
   !if (val)
     {
	push_spot();
	bol_skip_white();
	if (eolp())
	  {
	     go_up_1();
	     bol_skip_white();
	     % Added slang checks 04/09/98 MDJ
	     if (cmode_is_slang_mode()) cppComment = "%% ";

	     if (looking_at(cppComment))
	       {
		  val = -3;
		  col = what_column();
	       }
	  }
	pop_spot();
     }
#endif

%%   vmessage
%%   (
%%      "(%d) extra %d prep %d cont %d norm %d col %d match %d thisch '%c'
matchar '%c' line %d",
%%      val, extra_indent, prep_indent, is_continuation,
is_normal_statement,
%%      col, match_indent, this_char, match_char, match_line
%%   );

   switch (val)
     {
      case -3: 				%  inside C++ comment
	!if (looking_at(cppComment) or not(eolp()))
	  {
	     goto_column(col);
	     if (C_Autoinsert_CPP_Comments) insert(cppComment);
	  }
	return;
     }
     {
      case -2:			       %  inside comment
	if (cmode_is_slang_mode ()) return;
	if (this_char != '\\') col++;
	c_indent_continued_comment (col);
	return;
     }
     {
      case 2:			       %  inside string
	push_spot_bol ();
	trim ();
	pop_spot ();
	return;
     }
     {
      case 1:			       %  within a (...) grouping
	if (this_char == ')')
	  {
	     c_indent_to (col + prep_indent);
	     return;
	  }
	else if (col == match_indent)
	  {
	     % starting brace was alone on its line -
	     % indent contents like a {...} block
	     extra_indent = C_INDENT;
#iftrue
	     % outdent operators, logicals and comparisons
	     if (extra_indent >= 3)
	       extra_indent += operator_outdent(1);
#endif
	  }
	else
	  {
	     col++;                    %  align after '('
	     % limiter for indented parameter lists
	     if (C_Param_Offset_Max >= 0)
	       {
		  extra_indent = C_Param_Offset_Max + match_indent - col;
		  if (extra_indent > 0)
		    extra_indent = 0;
	       }
	  }
	% drop through to final indentation code
     }
     {
      case 0:			       %  outside of (...) grouping
	if (match_char == '[')         %  within [...] construct
	  {
	     c_indent_to (col + 1);
	     return;
	  }
	else if (match_char == '{')    %  within {...} block
	  {
	     push_spot ();
	     goto_user_mark (match_mark);
	     bskip_all_whitespace ();
	     if (blooking_at (")"))    %  ... (expr) {...} block
	       {
		  variable same_line = (what_line == match_line);

		  go_left_1 ();
		  if (1 == find_matching_delimiter (')'))
		    {
		       bol_skip_white ();
		       if (same_line)
			 match_indent = what_column ();

		       if (this_char != '}')
			 if (looking_at("switch"))
			   match_indent += C_Switch_Offset;
		    }
	       }

	     pop_spot ();
	     col = match_indent;

	     if (this_char == '}')
	       {
		  col += C_INDENT;    % undone below
	       }
	     else if (inside_class_or_namespace (match_mark, "class"))
	       {
		  col += C_Class_Offset;
		  if (this_char == '{') col -= C_BRACE; % undone below
	       }
	     else if (inside_class_or_namespace (match_mark, "namespace"))
	       {
		  col += C_Namespace_Offset;
		  if (this_char == '{') col -= C_BRACE; % undone below
	       }
	     else
	       {
		  col += C_INDENT;
	       }

	     prep_indent = 0;

	     % special treatment for the start of a (...) grouping
	     if (this_char == '(')
	       extra_indent = 0;

	     % drop through to final indentation code
	  }
	else
	  {
	     % no useful context found
	     % see if it is the start of a {...} or (...) grouping
	     if (is_normal_statement)
	       if ((this_char == '{') or (this_char == '('))
		 extra_indent = 0;

	     extra_indent++;
	     c_indent_to (extra_indent + prep_indent);
	     return;
	  }
     }

   switch (this_char)
     {
	case '}':
	  col -= C_INDENT;
	  if (is_normal_statement) extra_indent = 0;
     }
     {
        case '{':
	  col += C_BRACE;
	  if (is_continuation) extra_indent -= C_CONTINUED_OFFSET;
     }
   col += extra_indent;

   c_indent_to (col + prep_indent);
}

% This function returns zero if the line does not begin with "* @ "
% or returns the indent column if it does.  This combination of characters
% will most certainly appear in a comment.  See the c file jed/src/intrin.c
% for examples of how it is exploited.
private define c_is_comment_example ()
{
   push_spot ();
   bol_skip_white ();
   0;
   if (looking_at ("* @ "))
     {
	pop ();
	what_column ();
     }
   pop_spot ();
}

define c_newline_and_indent ()
{
   variable cppComment = "//";

   if (bolp ())
     {
	newline ();
	c_indent_line ();
	return;
     }

   if (cmode_is_slang_mode ())
     {
	variable slcom = "%";
	push_spot_bol ();
	if (looking_at (slcom) and C_Autoinsert_CPP_Comments)
	  {
	     push_mark ();
	     skip_chars ("%!");
	     skip_white ();
	     slcom = bufsubstr ();
	     pop_spot ();
	     newline ();
	     insert (slcom);
	     return;
	  }
	pop_spot ();
	cppComment = "%%";
     }

   variable col;
   variable cppComment_len = strlen (cppComment);

   if (C_Autoinsert_CPP_Comments)
     {
	col = what_column ();
	push_spot_bol();
	if (looking_at(cppComment))
	  {
	     push_mark ();
	     go_right (cppComment_len);
	     skip_white ();
	     cppComment = bufsubstr ();
	     pop_spot ();
	     newline();
	     if (col > cppComment_len) insert(cppComment);
	     return;
	  }
	pop_spot();
     }

   col = c_is_comment_example ();
   newline ();
   if (col)
     {
	c_indent_to (col);
	bol_skip_white();
	insert ("* @ ");
     }
   else c_indent_line ();
}

private define c_parse_to_point ()
{
   parse_to_point () or c_is_comment_example ();
}

define c_insert_bra ()
{
   if (c_parse_to_point ())
     insert_char ('{');
   else
     {
	push_spot ();
	bskip_comment (0);
	if (blooking_at (","), pop_spot ())
	  {
	     insert_char ('{');
	  }
	else
	  {
	     push_spot ();
	     skip_white ();
	     if (eolp ())
	       {
		  bskip_white ();
		  if (not (bolp ()) and C_BRA_NEWLINE, pop_spot ()) newline
();
		  push_spot ();
		  bskip_white ();
		  bolp ();	       %  on stack
		  pop_spot ();
		  insert_char ('{');
		  if ( () ) c_indent_line ();   %  off stack
		  eol ();
		  if (C_BRA_NEWLINE) c_newline_and_indent ();
	       }
	     else
	       {
		  pop_spot ();
		  insert_char ('{');
	       }
	  }
     }
}

define c_insert_ket ()
{
   variable status = c_parse_to_point ();
   variable line = what_line ();

   push_spot ();
   skip_white ();
   push_spot ();

   if (status
       or not (eolp ())
       or (1 == find_matching_delimiter ('}')) and (line == what_line ()))
     {
	pop_spot ();
	pop_spot ();
	insert_char ('}');
	blink_match ();
	return;
     }
   pop_spot ();
   bskip_white ();
   if (bolp (), pop_spot ())
     {
	insert_char ('}');
	trim ();
     }
   else
     {
	eol ();
	insert ("\n}");
     }
   c_indent_line ();
   eol ();
   blink_match ();
   if (C_BRA_NEWLINE) c_newline_and_indent ();
}

define c_insert_colon ()
{
   insert_char (':');
   !if (c_parse_to_point ())
     c_indent_line ();
}

$1 = "C";
!if (keymap_p ($1)) make_keymap ($1);
definekey ("indent_line", "\t", $1);
definekey ("newline_and_indent", "\r", $1);
definekey ("c_insert_bra", "{", $1);
definekey ("c_insert_ket", "}", $1);
definekey ("c_insert_colon", ":", $1);
definekey ("c_make_comment", "\e;", $1);
%definekey ("c_comment_region", "^X;", $1);
% definekey ("c_format_paragraph", "\eq", $1);
definekey ("c_top_of_function", "\e^A", $1);
definekey ("c_end_of_function", "\e^E", $1);
definekey ("c_mark_function", "\e^H", $1);

% Now create and initialize the syntax tables.
create_syntax_table ("C");
define_syntax ("/*", "*/", '%', "C");
define_syntax ("//", "", '%', "C");
define_syntax ("([{", ")]}", '(', "C");
define_syntax ('"', '"', "C");
define_syntax ('\'', '\'', "C");
define_syntax ('\\', '\\', "C");
define_syntax ("0-9a-zA-Z_", 'w', "C");        % words
define_syntax ("-+0-9a-fA-F.xXL", '0', "C");   % Numbers
define_syntax (",;.?:", ',', "C");
define_syntax ('#', '#', "C");
define_syntax ("%-+/&*=<>|!~^", '+', "C");
set_syntax_flags ("C", 0x4|0x40);

#ifdef HAS_DFA_SYNTAX
%%% DFA_CACHE_BEGIN %%%
private define setup_dfa_callback (name)
{
   dfa_enable_highlight_cache("cmode.dfa", name);
   dfa_define_highlight_rule("^[ \t]*#", "PQpreprocess", name);
   dfa_define_highlight_rule("//.*", "comment", name);
   dfa_define_highlight_rule("/\\*.*\\*/", "Qcomment", name);
   dfa_define_highlight_rule("^([^/]|/[^\\*])*\\*/", "Qcomment", name);
   dfa_define_highlight_rule("/\\*.*", "comment", name);
   dfa_define_highlight_rule("^[ \t]*\\*+([ \t].*)?$", "comment", name);
   dfa_define_highlight_rule("[A-Za-z_\\$][A-Za-z_0-9\\$]*", "Knormal",
name);
   dfa_define_highlight_rule("[0-9]+(\\.[0-9]*)?([Ee][\\+\\-]?[0-9]*)?",
			     "number", name);
   dfa_define_highlight_rule("0[xX][0-9A-Fa-f]*[LlUu]*", "number", name);
   dfa_define_highlight_rule("[0-9]+[LlUu]*", "number", name);
   dfa_define_highlight_rule("\"([^\"\\\\]|\\\\.)*\"", "string", name);
   dfa_define_highlight_rule("\"([^\"\\\\]|\\\\.)*\\\\?$", "string", name);
   dfa_define_highlight_rule("'([^'\\\\]|\\\\.)*'", "string", name);
   dfa_define_highlight_rule("'([^'\\\\]|\\\\.)*\\\\?$", "string", name);
   dfa_define_highlight_rule("[ \t]+", "normal", name);
   dfa_define_highlight_rule("[\\(\\[{}\\]\\),;\\.\\?:]", "delimiter",
name);
   dfa_define_highlight_rule("[%\\-\\+/&\\*=<>\\|!~\\^]", "operator", name);
   dfa_build_highlight_table(name);
}
dfa_set_init_callback (&setup_dfa_callback, "C");
%%% DFA_CACHE_END %%%
#endif

% Type 0 keywords (include C++ trigraphs)
#iffalse
() = define_keywords_n ("C", "doif", 2, 0);
#else
() = define_keywords_n ("C", "doifor", 2, 0);
#endif
() = define_keywords_n ("C", "andasmforintnewnottryxor", 3, 0);
() = define_keywords_n ("C", "autoboolcasecharelseenumgotolongthistruevoid",
4, 0);
#iffalse
() = define_keywords_n ("C",
"breakcatchclassconstfalsefloatshortthrowunionusingwhile", 5, 0);
() = define_keywords_n ("C",
"deletedoubleexternfriendinlinepublicreturnsignedsizeofstaticstructswitchtyp
eid", 6, 0);
#else
() = define_keywords_n ("C",
"bitorbreakcatchclasscomplconstfalsefloator_eqshortthrowunionusingwhile", 5,
0);
() = define_keywords_n ("C",
"and_eqbitanddeletedoubleexportexternfriendinlinenot_eqpublicreturnsignedsiz
eofstaticstructswitchtypeidxor_eq", 6, 0);
#endif
() = define_keywords_n ("C", "defaultmutableprivatetypedefvirtualwchar_t",
7, 0);
() = define_keywords_n ("C",
"continueexplicitoperatorregistertemplatetypenameunsignedvolatile", 8, 0);
() = define_keywords_n ("C", "namespaceprotected", 9, 0);
() = define_keywords_n ("C", "const_cast", 10, 0);
() = define_keywords_n ("C", "static_cast", 11, 0);
() = define_keywords_n ("C", "dynamic_cast", 12, 0);
() = define_keywords_n ("C", "reinterpret_cast", 16, 0);

% Type 1 keywords (commonly used libc functions)
() = define_keywords_n("C",
		       "EOFabscosdivexplogpowsintan",
		       3, 1);
%% should we add cin cerr cout ?
() = define_keywords_n("C",
		       "FILENULLacosasinatanatofatoiatolceilcosh"
		       + "exitfabsfeoffmodfreegetcgetslabsldivmodf"
		       + "putcputsrandsinhsqrttanhtime",
		       4, 1);

() = define_keywords_n("C",
		       "abortatan2clockctimediv_terrnofgetcfgets"
		       + "floorfopenfputcfputsfreadfrexpfseekftell"
		       + "ldexplog10qsortraisescanfsrandstdin",
		       5, 1);

() = define_keywords_n("C",
		       "assertatexitcallocfcloseferrorfflushfscanf"
		       + "fwritegetenvgmtimemallocmemchrmemcmpmemcpy"
		       + "memsetmktimeperrorprintfremoverenamerewind"
		       + "setbufsetjmpsignalsize_tsscanfstderrstdout"
		       + "strcatstrchrstrcmpstrcpystrlenstrspnstrstr"
		       + "strtodstrtokstrtolsystemtime_ttmpnamungetc"
		       + "va_argva_end",
		       6, 1);
() = define_keywords_n("C",
		       "asctimebsearchclock_tfgetposfprintffreopen"
		       + "fsetposgetcharisalnumisalphaiscntrlisdigit"
		       + "isgraphislowerisprintispunctisspaceisupper"
		       + "jmp_buflongjmpmemmoveputcharreallocsetvbuf"
		       + "sprintfstrcspnstrncatstrncmpstrncpystrpbrk"
		       + "strrchrstrtoultmpfiletolowertoupperva_list"
		       + "vprintf",
		       7, 1);
() = define_keywords_n("C",
		       "clearerrdifftimeisxdigitstrerror"
		       + "strftimeva_startvfprintfvsprintf",
		       8, 1);
() = define_keywords_n("C", "localtime",
		       9, 1);

% _debug_info = 1;

private define get_function_names (names)
{
   for (; c_bol_fsearch ("{"); pop_spot (), eol ())
     {
	push_spot ();

	go_left_1 ();
	if (blooking_at ("\\"))
	  {
	     % probably a macro --- skip it
	     continue;
	  }
	% get the function name
	bskip_comment (1);

	if (blooking_at (")"))
	  {
	     go_left_1 ();
	     if (1 != find_matching_delimiter (')'))
	       continue;

	     bskip_comment (1);
	     names[bextract_identifier ()] = what_line ();
	  }
     }
}

private define get_macro_names (names)
{
   while (c_re_fsearch ("^[ \t]*#[ \t]*define[ \t]+"))
     {
	() = ffind ("define");
	go_right (6);
	skip_chars (" \t\\");
	names [extract_identifier ()] = what_line ();
     }
}

private define get_typedef_names (names)
{
   while (c_re_fsearch ("\\<typedef\\>"))
     {
	go_right (7);

	skip_all_whitespace ();
	if (looking_at ("struct"))
	  {
	     go_right (6);
	     skip_comment ();
	     skip_identifier ();       %  struct tag
	     skip_comment ();
	     if (looking_at_char ('{'))
	       {
		  !if (find_matching_delimiter ('{'))
		    continue;
		  go_right_1 ();
	       }
	  }

	() = c_fsearch (";");

	bskip_comment (1);
	names [bextract_identifier ()] = what_line();
     }
}

private define process_menu_popup (popup, func)
{
   variable names = Assoc_Type[Int_Type];

   push_spot_bob ();
   (@func) (names);
   pop_spot ();

   variable keys = assoc_get_keys (names);
   keys = keys[array_sort (keys)];
   foreach (keys)
     {
	variable key = ();
	variable line = names[key];
	menu_append_item (popup, key, &goto_line, line);
     }
}

private define macros_popup_callback (popup)
{
   process_menu_popup (popup, &get_macro_names);
}

private define functions_popup_callback (popup)
{
   process_menu_popup (popup, &get_function_names);
}

private define typedefs_popup_callback (popup)
{
   process_menu_popup (popup, &get_typedef_names);
}

public define c_init_menu (menu)
{
   menu_append_popup (menu, "&Functions");
   menu_set_select_popup_callback (strcat (menu, ".&Functions"),
&functions_popup_callback);

   !if (cmode_is_slang_mode ())
     {
	menu_append_popup (menu, "M&acros");
	menu_append_popup (menu, "&Typedefs");
	menu_set_select_popup_callback (strcat (menu, ".M&acros"),
&macros_popup_callback);
	menu_set_select_popup_callback (strcat (menu, ".&Typedefs"),
&typedefs_popup_callback);
     }
   menu_append_separator (menu);
   menu_append_item (menu, "&Comment Region", "comment_region");
   menu_append_item (menu, "&Top of Function", "c_top_of_function");
   menu_append_item (menu, "&End of Function", "c_end_of_function");
   menu_append_item (menu, "&Mark Function", "c_mark_function");
   menu_append_item (menu, "&Format Buffer", "c_indent_buffer");
}

private define c_chglog_get_item ()
{
   variable m = create_user_mark ();

   EXIT_BLOCK
     {
	goto_user_mark (m);
     }

   ERROR_BLOCK
     {
	_clear_error ();
	goto_user_mark (m);
	return NULL;
     }

   % First check for a preprocessor macro.
   bol ();
   while (blooking_at ("\\\n"))
     {
	go_left_1 ();
	bol ();
     }
   skip_white ();
   if (looking_at_char ('#'))
     {
	go_right_1 ();
	skip_white ();
	if (looking_at ("define"))
	  {
	     go_right (6);
	     skip_white ();
	     return extract_identifier ();
	  }
     }
   goto_user_mark (m);

   % check for variable
   bol ();
   skip_identifier ();
   if (not(bolp) and ffind_char('='))
     {
	bskip_white ();
	return bextract_identifier ();
     }

   % Now try function
   goto_user_mark (m);
   c_end_of_function ();
   variable m_end = create_user_mark ();
   if (m > m_end)
     return NULL;
   c_top_of_function ();
   bskip_comment (1);

   if (blooking_at (")"))
     {
	go_left_1 ();
	if (1 != find_matching_delimiter (')'))
	  return NULL;
     }

   bskip_comment (1);
   !if (blooking_at ("typedef struct"))
     return bextract_identifier ();

   goto_user_mark (m_end);
   skip_chars ("} \t\n");
   return extract_identifier ();
}

% This function is called by slang_mode to share the keymap and some hooks
define c_mode_common ()
{
   use_keymap("C");
   set_buffer_hook ("indent_hook", "c_indent_line");
   set_buffer_hook ("newline_indent_hook", "c_newline_and_indent");

   foreach (["C", "SLang"])
     {
	variable mode = ();
	mode_set_mode_info (mode, "init_mode_menu", &c_init_menu);
	mode_set_mode_info (mode, "chglog_get_item", &c_chglog_get_item);
     }
}

%!%+
%\function{c_mode}
%\synopsis{c_mode}
%\usage{Void cmode ();}
%\description
% This is a mode that is dedicated to facilitate the editing of C language
files.
% Functions that affect this mode include:
%#v+
%  function:             default binding:
%  c_insert_bra               {
%  c_insert_ket               }
%  newline_and_indent         RETURN
%  indent_line                TAB
%  goto_match                 Ctrl-\
%  c_make_comment             ESC ;
%  c_top_of_function          ESC Ctrl-A
%  c_end_of_function          ESC Ctrl-E
%  c_mark_function            ESC Ctrl-H
%#v-
% Variables affecting indentation include:
%#v+
%  C_INDENT
%  C_BRACE
%  C_BRA_NEWLINE
%  C_CONTINUED_OFFSET
%  C_Comment_Column  (used by c_make_comment)
%  C_Class_Offset
%  C_Switch_Offset
%  C_Colon_Offset
%  C_Namespace_Offset
%#v-
%
% Hooks: \var{c_mode_hook}
%\seealso{c_set_style}
%!%-
define c_mode ()
{
   set_mode("C", 2);

   c_mode_common ();
   set_buffer_hook ("par_sep", "c_paragraph_sep");
   set_buffer_hook ("format_paragraph_hook", &c_format_paragraph);
   mode_set_mode_info ("C", "fold_info", "/*{{{\r/*}}}\r*/\r*/");
   mode_set_mode_info ("C", "dabbrev_case_search", 1);
   use_syntax_table ("C");
   run_mode_hooks("c_mode_hook");
}

%!%+
%\function{c_set_style}
%\synopsis{Set the indentation style for C mode}
%\usage{Void c_set_style (style)}
%\description
% This function sets the C mode indentation variables appropriate for
% a common indentation style.  Currently supported styles include:
%#v+
%    "gnu"      Style advocated by GNU
%    "k&r"      Style popularized by Kernighan and Ritchie
%    "linux"    Linux kernel indentation style
%    "bsd"      Berkeley style
%    "foam"     Style used in OpenFOAM
%    "jed"      Style used by the author
%#v-
%\seealso{c_mode}
%!%-
define c_set_style (name)
{
   switch (strlow(name))
     {
      case "gnu":
	(2,2,1,2,0,2,2);
     }
     {
      case "k&r":
	(5,0,0,5,0,5,5);
     }
     {
      case "bsd":
	(4,0,0,4,0,4,4);
     }
     {
      case "foam":
	(C_Switch_Offset, C_Param_Offset_Max) = (4, -1);
	(4,0,0,4,0,4,0);
     }
     {
      case "linux":
	(8,0,0,8,0,8,8);
     }
     {
      case "jed":
	(3,2,1,2,1,3,3);
     }
     {
	if (is_defined ("c_set_style_hook") > 0)
	  return eval(sprintf ("c_set_style_hook(\"%s\");", name));
     }

   (C_INDENT, C_BRACE, C_BRA_NEWLINE, C_CONTINUED_OFFSET,
    C_Colon_Offset, C_Class_Offset, C_Namespace_Offset)=();
}

if (_C_Indentation_Style != NULL)
  c_set_style (_C_Indentation_Style);

provide ("cmode");
#stop

This e-mail message and any attachments may contain legally privileged, confidential or proprietary Information, or information otherwise protected by law of ArvinMeritor, Inc., its affiliates, or third parties. This notice serves as marking of its ?Confidential? status as defined in any confidentiality agreements concerning the sender and recipient. If you are not the intended recipient(s), or the employee or agent responsible for delivery of this message to the intended recipient(s), you are hereby notified that any dissemination, distribution or copying of this e-mail message is strictly prohibited. If you have received this message in error, please immediately notify the sender and delete this e-mail message from your computer.



--------------------------
To unsubscribe send email to <jed-users-request@xxxxxxxxxxx> with
the word "unsubscribe" in the message body.
Need help? Email <jed-users-owner@xxxxxxxxxxx>.


[2006 date index] [2006 thread index]
[Thread Prev] [Thread Next]      [Date Prev] [Date Next]