home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 5 Edit
/
05-Edit.zip
/
p2demo21.exe
/
PEL
/
ELECTRIC.PEL
< prev
next >
Wrap
Text File
|
1995-04-19
|
36KB
|
1,261 lines
# $Header: P:\source\wmacros\electric.pev 1.101 19 Apr 1995 12:59:56 PFHDWM0 $
# $Tabs:4 7$
##############################################################################
#
# Compuware Corporation
# 31440 Northwestern Highway
# Farmington Hills, Michigan 48334-2564
#
# This source code listing contains information that is
# proprietary to Compuware Corporation and may not be copied
# duplicated, translated, transmitted, stored, retrieved
# or in any manner or by any method conveyed or disclosed
# to a third party or parties without express written
# permission from Compuware Corporation.
#
#
##############################################################################
#### $Workfile: electric.pel $: helper routines for entering C code
#
# There are three principal facilities in this package:
# 1. Insertion of code templates
# (see "function initialized_template()" in this module
# on how to add new templates)
# 2. Bracket matching (several flavors)
#
#
# Clipper Support and general improvements made to this module
# have be provided by P. Polakoff III, 3P Software, Inc.
#
### "electric" templates program-entry features.
#
# The template entry facility works differently than some other
# products' in that templates are inserted only upon demand, and
# not automatically upon recognition of an abbreviation.
#
# Templates are auto-indented independently of the autoindent mode.
#
# Template insertion is activated manually by a keypress. The key
# that is assigned by default to do the template expansion is the
# ESC key. Any other key may be used, but to not lose this key's
# original behavior, it should be handled in the expand_template_key()
# function. This function is prepared to work for the SPACE, TAB,
# or ESC key.
#
# The mode may be turned on and off by calls to ec() or
# toggle_electric(). It additionally is enabled or disabled depending
# on whether the extension on the current buffer's name matches one of
# the patterns in the expand template list.
#
# Multiple-character abbreviation sequences are allowed.
#
global language_template # the map of abbreviations onto expanded strings
global D_DIALECT = "clipper87" # dBASE dialect (used by errorfix.pel also)
global ELEC_LANG = "text" # current electric language
global electric_mode = 0 # 0 = disabled, 1 = enabled
# initialized_template() was called.
global K_R = 1 # set the K&R brace matching
#local newEditFileId
local _es = "`"
global electric_symbol
# keep track of former assignments to ec keys
local expand_key_set
local next_key_set
local default_keys[]
local DEFAULT_EXPAND_TEMPLATE_KEY = "<Space>"
local DEFAULT_NEXT_FIELD_KEY = "<Ctrl-Enter>"
global syntax_loaded[]; # Array keeping track of what syntax has been loaded
#
# Addition of new templates:
# --------------------------
# Add a new element to the file_extensions[] array and initialize it
# with the associated extensions as demonstrated below. Then add
# the new electric array as defined in initialize_template() below.
#
# Possible file extents for each language. Each is a regular expression
# to match the buffer's filename extension.
#
# "electric_extensions" takes on one of these values initialized in
# initialize_extensions().
#
global function load_factory_default_templates(reset)
{
templates["awk"] = "setup_awk_template";
# templates["basic"] = "setup_null_template basic"; Temporarily discontinued;
templates["c"] = "setup_C_template";
templates["clipper50"] = "dBaseDialect";
templates["clipper87"] = "dBaseDialect";
templates["cobol"] = "setup_cobol_template";
# templates["cpp"] = "setup_C_template";
templates["dbase"] = "dBaseDialect";
templates["force"] = "dBaseDialect";
templates["pascal"] = "setup_pascal_template";
templates["rexx"] = "setup_rexx_template";
templates["text"] = "setup_null_template text";
templates["[None]"] = "setup_null_template text";
}
## ec()
#
# enable/display template generation ( 0 = disable, 1 = enable );
#
#function ec( mode )
#{
# if (argcount())
# toggle_electric( mode );
# else
# toggle_electric()
#}
global function set_expand_template_key( key )
{
local strkey
local newkey = "expand_template_key"
if (expand_key_set && (argcount() == 0) )
return
if (key == "")
key = DEFAULT_EXPAND_TEMPLATE_KEY
# don't create a circular loop by assigning the same
# function to both variables
strkey = keymap_binding( key )
if ( strkey != newkey )
{
default_keys[ key ] = strkey
assign_key( key, newkey )
}
expand_key_set = 1
}
global function remove_expand_template_key( key )
{
if ( default_keys[ key ] )
{
assign_key( key, default_keys[ key ] )
delete default_keys[ key ]
}
else
{
warning( "remove_expand_template_key: key \"%s\" not assigned", key )
}
}
global function set_next_field_key( key )
{
local strkey
local newkey = "next_field_key"
if (next_key_set && (argcount() == 0) )
return
if (key == "")
key = DEFAULT_NEXT_FIELD_KEY
# don't create a circular loop by assigning the same
# function to both variables
strkey = keymap_binding( key )
if ( strkey != newkey )
{
default_keys[ key ] = strkey
assign_key( key, newkey )
}
next_key_set = 1
}
global function remove_next_field_key( key )
{
if ( default_keys[ key ] )
{
assign_key( key, default_keys[ key ] )
delete default_keys[ key ]
}
else
{
warning( "remove_next_field_key: key \"%s\" not assigned", key )
}
}
## toggle_electric()
#
# enable/display template generation ( 0 = disable, 1 = enable );
#
function toggle_electric( on )
{
local verbose = 0
if( argcount() < 1 )
{
on = !electric_mode
verbose = 1
}
electric_mode = on
set_expand_template(path_ext(buffer_filename), on);
if (electric_mode)
{
initialize_template();
# set_expand_template_key( DEFAULT_EXPAND_TEMPLATE_KEY )
# set_next_field_key( DEFAULT_NEXT_FIELD_KEY )
set_expand_template_key( )
set_next_field_key( )
}
else
{
# if (newEditFileId)
# {
# #delete_event( EVENT.NEW_EDIT_FILE, newEditFileId );
# newEditFileId = 0;
# }
# reinitialize the electric vars
# electric_extensions = initialized_file_ext = ""
# remove_expand_template_key( DEFAULT_EXPAND_TEMPLATE_KEY )
# remove_next_field_key( DEFAULT_NEXT_FIELD_KEY )
}
if( verbose )
message( "Template expansion is %s.", electric_mode ? "on" : "off")
}
## initialize_template()
#
# Initialize the correct template for the language being used.
# The language is determined by the extension of the current buffer's
# name. If the template has already been initialized, it is ignored.
#
# Addition of new templates:
# --------------------------
# To add a new template, create a new element in the file_extensions
# array defined in initialize_extensions() above.
#
# Next, duplicate one of the if-else statements below and change the
# language_template[] settings appropriately. Also, be sure the comparison
# with "_extensions" (your new variable name) is updated as well.
#
local function initialize_template()
{
local OB, EB, EB2
local temp = Template(path_ext(buffer_filename));
local fn, id;
local def_name = "_default"
if(temp == ELEC_LANG)
return;
if (temp)
{
fn = "__" temp;
id = function_id( fn );
}
if (!id)
id = function_id( def_name );
# cvdebug("calling >" function_name(id) "<");
if ( id )
execute_function( id );
# setup brace and block style
if ( K_R )
{
OB = electric_symbol.open_brace = "{\n\t"
EB = electric_symbol.end_brace = "\n\b} "
EB2 = electric_symbol.end_brace2 = "\n\b\b} "
}
else
{
OB = electric_symbol.open_brace = "\t{\n"
EB = electric_symbol.end_brace = "\n} "
EB2 = electric_symbol.end_brace2 = "\n\b} "
}
electric_symbol.new_block = OB "`statement-1`" EB "\n"
electric_symbol.block = OB "`statement-1`" EB
# this condition is here to remove the warning during a compile
if(0)
setup_null_template();
# This creates an infinite loop on startup. If anyone can remember why it
# is here, please fix and comment it; (JAM:12-29-94);
# new_edit_file();
if( (temp == "clipper87") || (temp == "clipper50") ||
(temp == "force") || (temp == "dbase") )
optional_function(templates[temp], temp);
else
optional_function(templates[temp]);
}
local function setup_null_template(template)
{
ELEC_LANG = template;
language_template[ "null" ] = "\0";
}
## template_add()
#
# Provides ability to add templates on the fly
# It is also possible to change a current template with this function
#
function template_add( tstr, expstr )
{
if (argcount() < 1)
tstr=prompt("Template characters: ","")
if (tstr && argcount() < 2)
expstr=prompt("Template expansion: ", language_template[ tstr ] )
if(tstr)
{
gsub("\\\\\\\\","\\",expstr)
language_template[tstr]=expstr
message("Template \""tstr"\" created.")
}
}
## expand_template_key()
#
# Expand a template or do default behavior of key
#
function expand_template_key()
{
local key
local key_action
if ( !expand_template( 1 ) )
{
key = default_keys[ int_to_key( current_key ) ]
if ( key )
{
key_action = function_id( key )
if ( key_action &&
key_action != function_id("expand_template_key") &&
function_caller() == "Keyboard" )
execute_function( key_action )
}
}
}
## expand_template()
#
# Expand a template if one can be located at or near the cursor.
#
function expand_template( noError )
{
local keyLen, key, i
local oldPE = pause_on_error
local status = 0
local ext = path_ext(buffer_filename)
local item, catname, match_case
# turn pause_on_error off so message just displays on status_bar
# and no user input is involved
#
pause_on_error = 0
initialize_template()
# status = ( electric_mode && buffer_name ~ electric_extensions )
status = ( electric_mode && Template(ext))
if ( !noError )
{
if ( !electric_mode )
warning("Template expansion mode is not on!")
else if(!Template(path_ext(buffer_filename)))
warning("Invalid extension for template expansions!")
}
if ( status )
{
# reset status to zero since this is the value we will return
# and it'll be changed later if need be
status = 0
item = get_style_item();
catname = get_category_name(ext, item)
match_case = get_case_sensitive(path_ext(buffer_filename))
key = left_symbol_under_cursor( SYMBOL_REGEX2 )
# if key is not a comment or literal type then don't allow expansion when
# inside a comment or literal
if( match(item, quote_regex(key), !match_case) || (catname != "Comments" && catname != "Literals") )
{
if( key in language_template )
{
# since the key was found, set status to 1
#
status = 1
keyLen = length( key )
# starting at current cursor position, read the buffer for a string the
# size of the key. If match, delete, else move to left and try again
# so that it can be deleted before the template is inserted
#
for (i=0; i<=keyLen; i++)
{
if (read_buffer( keyLen ) == key )
{
delete_chars( keyLen )
break
}
current_column--
}
insert_template( language_template[ key ])
# make sure we are in the first field of the template
if ( match(language_template[key], _es) )
next_field_key()
}
else if ( !noError )
warning("No template for \"%s\".", key );
}
# else
# cvdebug("we are in a comment dude!");
}
pause_on_error = oldPE
return status
}
## insert_template()
#
# insert a particular template
#
# The following characters are treated specially:
#
# 1. "@" => place the cursor here after the template has been inserted
# 2. "\n" => insert a newline and auto-indent.
# 3. "\r" => insert a newline
# 4. "\t" => indent an extra level (not actually treated specially)
# 5. "\b" => unindent one level
#
# eg.: "{\n\t\n\b}" follows K&R
local function insert_template( t )
{
local i, c
local col = current_column
local row = current_line
local rs = and(buffer_flags,BUFFER_REAL_SPACE_ONLY);
buffer_flags = and( buffer_flags, not(BUFFER_REAL_SPACE_ONLY) );
while( t && ( i = match( t, "@|\\n|\\b|\\r" )))
{
if( i > 1 )
insert_string( substr( t, 1, i - 1 ))
c = substr( t, i, 1 )
t = substr( t, i + 1 )
if( c == "\n" )
insert_auto_indent()
else if( c == "\r" )
insert_newline()
else if( c == "\b" )
backspace();
else if( c == "@" )
{
col = current_column
row = current_line
}
}
insert_string( t )
place_bookmark(buffer_filename":electric_end", 1, 1)
buffer_flags = or( buffer_flags, rs );
goto_pos( row, col )
}
function insert_all_templates()
{
local t
initialize_template()
for( t in language_template )
{
insert_string( t "\n" )
begin_selection( LINE_SELECTION )
insert_template( language_template[ t ])
insert_string( "@" )
goto_buffer_bottom()
insert_string( "\n\n" )
indent_tabs()
goto_mark( selection_mark_top() )
remove_selection()
prev_char()
delete_chars( 1 )
goto_buffer_bottom()
goto_bol()
}
}
local eventDeleted = TRUE
local _nextFieldKey
function next_field_key()
{
local sf = SEARCH_FORWARD+SEARCH_HIGHLIGHT+SEARCH_REGEX+SEARCH_WRAPS+SEARCH_ADVANCE
local pattern = _es ".*" _es
local old_search_pattern = search_pattern
local temp = message_level
local status = 0;
local key_action
local key
if ( electric_mode )
{
# this function is usually only called by a keypress so we'll save
# it so it can be used when it comes time to delete a field
_nextFieldKey = current_key
# This is to make sure the event is only attached once
if ( eventDeleted )
{
eventDeleted = FALSE;
attach_event_handler(EVENT.KEYPRESS, function_id("delete_field") )
}
# change message level to prevent warning message if string isn't found
#
message_level = 3
status = sf_search(pattern, sf);
message_level = temp
# remove our pattern from the history list and restore old search
# pattern
#
delete_history_item( "SEARCH", pattern )
search_pattern = old_search_pattern
if (!status && bookmark_defined(buffer_filename":electric_end") )
{
goto_bookmark(buffer_filename":electric_end")
delete_bookmark(buffer_filename":electric_end");
status = 1
}
}
if ( !status )
{
eventDeleted = TRUE;
delete_event(EVENT.KEYPRESS, function_id("delete_field") )
# this is for default behavior if there is no field to go to
#
key = default_keys[ int_to_key( current_key ) ]
if ( key )
{
key_action = function_id( key )
if ( key_action &&
key_action != function_id("expand_template_key") &&
function_caller() == "Keyboard" )
execute_function( key_action )
}
}
return status;
}
function delete_field()
{
# only delete the field and event if we press a key other than a
# directional key or the field key
#
if ( isDirectionalKey() )
eventDeleted = FALSE;
else if ( current_key != _nextFieldKey )
{
delete_event(EVENT.KEYPRESS, function_id("delete_field") )
if( selection_type() )
delete_chars();
eventDeleted = TRUE;
update_current_view()
}
}
local function isDirectionalKey()
{
local key = int_to_key(current_key)
if (key == "<Down>" || key == "<Up>" || key == "<Left>" ||
key == "<Right>" || key == "<PageDown>" || key == "<PageUp>" ||
key == "<Home>" || key == "<End>" )
return TRUE;
else
return FALSE;
}
### support for matching constructs
#
global default_matching_pairs = "{ } [ ] ( ) /* */ %if %endif #if #endif #ifdef #endif" # string of matching pairs
global matching_pairs = default_matching_pairs
local matching_left = "(\\{)|(\\[)|(\\()|(/\\*)|(%if)|(#if)|(#ifdef)"
local FORWARD = TRUE
local BACKWARD = FALSE
local last_matching_direction = FORWARD
local last_matching_open = ""
local last_matching_close = ""
## record the particular matching constructs
#
# argument is a whitespace-separated sequence of opening, closing pairs
# a null string causes the defaults to be selected
local function init_matching_pairs( pairs )
{
local larray[]
local odd = TRUE
local i
local ext
if ( pairs )
matching_pairs = pairs
else
{
ext = path_ext(buffer_name)
if ( ext in extensions )
matching_pairs = MatchingPairs(ext);
else
matching_pairs = ""
}
matching_pairs = compress(ltrim(trim(matching_pairs)))
matching_left = ""
if (matching_pairs == "")
return
# create a regex in matching_left that will find the left side of pair
split( matching_pairs, larray, " " )
for ( i in larray )
{
if ( odd )
{
# gsub( "\\(", "\\(", larray[ i ] )
# matching_left = matching_left "(" larray[ i ] ")" "|"
matching_left = matching_left " " larray[ i ]
odd = FALSE
}
else
odd = TRUE
}
# remove the last trailing "|"
# matching_left = substr( matching_left, 1, length(matching_left) - 1 )
# gsub( "\\*", "\\*", matching_left )
# gsub( "\\[", "\\[", matching_left )
# gsub( "\\{", "\\{", matching_left )
matching_left = quote_regex(ltrim(matching_left))
matching_left = trans(matching_left, " ", "|")
}
## form an inclusive selection around a matching pair
#
# If a selection has already been made, merely swap selection marks.
# It is an error if no half of a matching pair can be found.
function mark_matching()
{
local m1, m2
local status = FALSE
local len_close
if ( selection_type() )
{
# The selection is already present. Goto the opposite mark.
m1 = selection_mark_top()
m2 = selection_mark_bottom()
if ( m1 && m2 )
{
if (mark_line( m1 ) == current_line &&
mark_column( m2 ) == current_column)
{
goto_mark( m2 )
}
else
goto_mark( m1 )
}
else
beep()
}
else
{
save_position()
if ( goto_matching() )
{
len_close = length( last_matching_close )
# go to the last character of the matching construct
if ( last_matching_direction == FORWARD )
next_char( len_close - 1 )
# A match has been found. Select all text
# between and including the matching pair.
begin_selection( INCLUSIVE_SELECTION )
restore_position( TRUE )
# go to the last character of the matching construct
if ( last_matching_direction == BACKWARD )
{
save_position()
next_char( len_close - 1 )
end_selection()
restore_position( TRUE )
}
else
end_selection()
status = TRUE
}
else
restore_position( TRUE )
}
return status
}
## form an inclusive selection around a NESTED matching pair
#
function mark_matching_next()
{
local item
local catname
local ext = path_ext(buffer_filename)
local found_open
init_matching_pairs( )
if ( !matching_pairs )
{
warning( "No matching pairs defined for this extension" )
return
}
if ( selection_type() != NO_SELECTION )
{
goto_mark( selection_mark_top() )
remove_selection()
update_current_view()
next_char()
}
save_position()
while ( (found_open = search(matching_left, SEARCH_FWD_REGEX_MAX_IG + SEARCH_ADVANCE )) != 0 )
{
item = get_style_item();
catname = get_category_name(ext, item)
if( catname != "Comments" && catname != "Literals")
break;
}
if (found_open)
{
restore_position(0);
mark_matching();
}
else
{
message("No opening pairs found.");
restore_position(1);
}
}
local function on_item(item, s)
{
local ret = FALSE
local match_case = get_case_sensitive(path_ext(buffer_filename))
local symbol_offset
local start_offset = current_line_offset + 1 # make start_offset 1 based
local cur_line
local match_start, match_len
save_position()
current_column = 0
cur_line = read_buffer()
restore_position(1)
item = trans( quote_regex(compress(item)), " ", "|" )
s = symbol_under_cursor( "[^ \t]+" )
symbol_offset = start_offset + 1 - index(cur_line, s)
if ( match(s, item, !match_case) || match(s, item, !match_case))
{
match_start = RSTART
match_len = RLENGTH
if (symbol_offset >= RSTART && symbol_offset < RSTART+RLENGTH)
{
#warning("On Comment!!!!")
ret = TRUE
}
}
return ret
}
## goto the matching construct corresponding to the one under the cursor
#
# The cursor may be on a matching construct and be valid.
# The cursor is restored to its original position if no match is found.
# The optional parameter terminator is a pattern that if found terminates
# the command with an error status. This is useful, for example, in C when
# you are on a ')', you can stop if you encounter a '{'.
function goto_matching( terminator, noErr )
{
local forward # odd => forward; even => backward
local base
local len, i, p
local matching_pair # the array identifying matching pairs
local matching_count # number of elements in matching_pair
local ext = path_ext(buffer_filename)
local item
local catname
local match_case = get_case_sensitive(ext)
local success = FALSE
local unbalanced = FALSE
local oldPE = pause_on_error;
local found1 = 0
local found2 = 0
local cur_symbol = ""
# turn pause_on_error off so message just displays on status_bar
# and no user input is involved
#
pause_on_error = 0
last_matching_open = ""
last_matching_close = ""
item = get_style_item()
catname = get_category_name(ext, item)
if( catname != "Comments" && catname != "Literals" || on_item(item))
{
init_matching_pairs()
if (matching_pairs)
{
matching_count = split( matching_pairs, matching_pair )
for ( i = 1; i <= matching_count; i++ )
{
p = matching_pair[i]
len = length( p )
if (!match_case)
p = tolower(p)
cur_symbol = readn1(1)
if (!match_case)
cur_symbol = tolower(cur_symbol)
found1 = ( p == cur_symbol )
if ( !found1 && len > 1)
{
cur_symbol = symbol_under_cursor( "[^ \t]+" )
found2 = match(cur_symbol, quote_regex(p), !match_case)
}
if ( found1 || found2 )
break
} # end for(matching_pairs)
if ( found1 || found2 )
{
forward = and( i, 1 )
base = and( i + 1, 0xFFFFFFFE )
last_matching_direction = forward
last_matching_open = matching_pair[ base - 1 ]
last_matching_close = matching_pair[ base ]
if ( found1 )
success = scan_for_matching( forward, last_matching_open, last_matching_close, terminator )
else if ( found2 )
{
next_char()
prev_word( 1, "^|[ \t]" )
if ( in_whitespace() )
right()
success = scan_for_matching( forward, last_matching_open, last_matching_close, terminator )
}
if ( !noErr && !success )
warning( "unbalanced nesting pair: %s %s", last_matching_open, last_matching_close )
} # end if (on matching construct)
else if ( !noErr )
warning( "Cursor not positioned on matching construct." )
}
else if ( !noErr )
warning( "No matching pairs defined for this extension" )
}
else if ( !noErr )
warning( "In comment or literal" )
pause_on_error = oldPE
return success
}
## move the cursor to a matching construct,
#
# given a direction, and the opening and closing constructs.
# The cursor is restored to its original position if no match is found.
local function scan_for_matching( forward, open, close, term )
{
local item
local catname
local ext = path_ext(buffer_filename)
local match_case = get_case_sensitive(ext)
local olen = length( open )
local clen = length( close )
local tlen = length( term )
local pattern = quote_regex( open ) "|" quote_regex( close )
local flags = SEARCH_REGEX \
+ SEARCH_MAXIMAL_MATCH \
+ SEARCH_ADVANCE \
+ SEARCH_FORWARD * forward
local level = forward * 2 - 1 # forward => +1; backward => -1
local s
local block_items = merge_arrays(Block(ext), Line(ext))
local pattern_is_block
local i
if ( (!match(open close, "[" quote_regex(word_delimiter) "]")) )
{
# Add the begin and end-of-word regex chars to the pattern iff neither
# string contains any word delimiters. The search flag
# SEARCH_WHOLE_WORD didn't work. This fixes a bug where a matching pair of
# 'if end' would stop when it found a word containing either one, like 'append'.
pattern = "<" quote_regex( open ) ">|<" quote_regex( close ) ">"
}
for (i in block_items)
if (i == open " " close)
{
catname = get_category_name(ext, i)
if(catname == "Comments" || catname == "Literals")
{
pattern_is_block = TRUE
break
}
}
if (term)
pattern = pattern "|" quote_regex( term )
if (!match_case)
{
open = tolower(open)
close = tolower(close)
}
else
flags = or(flags, SEARCH_CASE)
save_position()
while ( level != 0 )
{
if ( search(pattern, flags) )
{
item = get_style_item();
catname = get_category_name(ext, item)
if(catname != "Comments" && catname != "Literals" || pattern_is_block)
{
if (term)
{
s = readn1( tlen )
if ( s == term )
{
restore_position( TRUE ) # restore saved pos
return FALSE
}
}
s = readn1( olen )
if (!match_case)
s = tolower(s)
if ( s == open ) # == was opening symbol
level += 1
if ( olen != clen )
{
s = readn1( clen )
if (!match_case)
s = tolower(s)
}
if ( s == close ) # == was closing symbol
level -= 1
}
}
else
{
restore_position( TRUE ) # restore saved pos
return FALSE
}
} # end while(level != 0)
restore_position( FALSE ) # discard saved pos
return TRUE
}
##
# matched_is_comment(block_items, matched)
# This function returns TRUE if the string in matched is part of one of the
# block styles of category "Comment" or "Literals". Parameter block_items
# is an array containing all of the items that are line or block type for
# the current file extension. Since matched can be part of a multiword
# style item, we test for either a preceding or following space.
local function matched_is_comment(block_items, s)
{
local i
local ext = path_ext(buffer_filename)
local match_case = get_case_sensitive(ext)
local catname
local ret = FALSE
for (i in block_items)
{
if ( (s == i) || match(s " ", i, !match_case) || match(" " s, i, !match_case))
{
catname = get_category_name(ext, i)
if(catname == "Comments" || catname == "Literals")
{
ret = TRUE
break
}
}
}
return ret
}
##
# braces -- report on unmatched opening and closing braces
#
function braces()
{
local level = 0
local max_level = 0
local matched
local flags = SEARCH_FWD_REGEX_MAX_IG
local pattern
local opening
local catname, item
local ext = path_ext(buffer_filename)
local match_case = get_case_sensitive(ext)
local block_items = merge_arrays(Block(ext), Line(ext))
local level_string
level_string[0] = ""
level_string[1] = "."
level_string[2] = ".."
level_string[3] = "..."
level_string[4] = "...."
level_string[5] = "....."
level_string[6] = "......"
level_string[7] = "......."
level_string[8] = "........"
level_string[9] = "........."
save_position()
goto_buffer_top()
init_matching_pairs( )
if ( !matching_pairs )
{
warning( "No matching pairs defined for this extension" )
return
}
opening = matching_left
if (!match_case)
opening = tolower(opening)
else
flags = or(flags, SEARCH_CASE)
# call quote_regex to make sure any special characters are preceded
# with a backslash.
pattern = quote_regex( matching_pairs )
# since 'matching_pairs' is space delimited, replace all spaces with
# the regex 'or' operator.
pattern = trans( pattern, " ", "|" )
while( search( pattern, flags ))
{
# use global search_string_length to get found string
matched = read_buffer( search_string_length )
item = get_style_item();
catname = get_category_name(ext, item)
if ( catname != "Comments" && catname != "Literals" ||
matched_is_comment(block_items, matched) )
{
if (!match_case)
matched = tolower(matched)
if( matched ~ opening )
{
# if the characters found are part of the opening string
save_position()
level++
}
else
{
if( level-- )
restore_position( 0 )
else
{
save_position()
break
}
}
message( "nesting level == %d %s", level ,
level < 10 ? level_string[level] : "..........")
if (level > max_level)
max_level = level
}
next_char()
}
restore_position( 1 )
if( level > 0 )
{
while( level-- )
{
restore_position( 0 )
}
warning( "unmatched opening" )
}
else if( level < 0 )
{
restore_position( 0 )
warning( "unmatched closing" )
}
else
message( "braces match, max nesting = %d", max_level )
}
# This function is commented out since it is not used. It is a useful function
# which is why it hasn't been deleted.
# read n characters before the cursor
#local function readn( n )
#{
# return ( n <= current_line_offset ) ? read_buffer( -n ) : ""
#}
# read n characters following and including the cursor
local function readn1( n )
{
return ( n + current_line_offset <= current_line_length ) \
? read_buffer( n ) \
: ""
}
###
#
# new_edit_file()
#
# Whenever a new edit file is created, the extension is stripped from
# the file name and a function with that extension (preceded by "__")
# is invoked. If the function does not exist, "_default()" is called.
#
global function new_edit_file()
{
local value;
local ext = path_ext( buffer_filename );
local num
local margins[], pp;
local type, old_level = message_level;
local mask = or(BUFFER1MASK, BUFFER3MASK);
if(!and(buffer_flags, BUFFER_SYSTEM))
{
message_level = 1;
type = Type(ext);
type = type ? type : DEFAULT;
if(!(DEFAULT in languages))
add_type(DEFAULT);
buffer_tabs = Tabs(type);
wp_left_margin = LeftMargin(type);
wp_right_margin = RightMargin(type);
buffer_flags = set_flag_bits(buffer_flags, mask, BufferFlags(type));
auto_indent_mode = AutoIndent(type);
set_word_mode(get_word_mode(type)+0);
# This is commented out until electric_mode is turned into a buffer variable;
# toggle_electric(get_expand_template(type)+0);
if(!(type in syntax_loaded))
{
if(!("__styles" in syntax_loaded))
{
optional_function("load_user_styles");
syntax_loaded["__styles"] = TRUE;
}
optional_function("load_user_" type "_syntax");
syntax_loaded[type] = TRUE;
}
if(languages_id != type)
languages_id = type;
syntax_highlight = Syntax(type);
case_insensitive = !get_case_sensitive(type);
style_delimiter = StyleDelimiters(type);
escape_character = EscapeCharacter(type);
message_level = old_level;
}
}
# this function could be used to mark a field by returning the field and the
# field character on both sides of the field. It is commented out to prevent
# the warning message since it is not used
#local function __es( value )
#{
# return _es value _es
#}