!+
! MATCHING.TPU - Routine to automatically insert close parentheses etc.
!-

procedure eve_set_matching(the_arg)	! Turn on electric open parens
LOCAL	the_key,
        the_keys,
	ptr;

    the_keys := the_arg;

    if (the_keys = "") then
        the_keys := read_line("Match what characters: ");
    endif;
    ptr := 1;
    loop
        exitif (ptr > length(the_keys));
        the_key := substr(the_keys, ptr, 1);
        if (index(eveplus_matchable_open, the_key) <> 0) then
            define_key("eveplus_insert_matched", key_name(the_key), " typing");
        else
            message('"' + the_key + '" is not matchable');
            return;
        endif;
        ptr := ptr + 1;  
    endloop;

endprocedure;

procedure eve_set_nomatching(the_arg)		! Turn off electric open parens
LOCAL	the_key,
        the_keys,
	ptr;

    the_keys := the_arg;

    if (the_keys = "") then
        the_keys := read_line("Remove matching for what charcters: ");
    endif;
    ptr := 1;
    loop
        exitif (ptr > length(the_keys));
        the_key := substr(the_keys, ptr, 1);
        if (index(eveplus_matchable_open, the_key) <> 0) then
            undefine_key(key_name(the_key));
        else
            if (index(eveplus_matchable_close, the_key) = 0) then
                message('"' + the_key + '" is not matchable');
                return;
            endif;
        endif;
        ptr := ptr + 1;
    endloop;

endprocedure;

procedure eveplus_insert_matched                ! Insert the two caharcters
LOCAL   the_key,
        which;

    the_key := ascii(last_key);
    which := index(eveplus_matchable_open, the_key);
    if (which <> 0) then
        eveplus_insert_text(the_key);
        eveplus_insert_text(substr(eveplus_matchable_close, which, 1));
        move_horizontal(-1);
    else
        message("That key isn't matchable.");
        return;
    endif;

endprocedure

! Insert the second of two match characters (close character), and display
! the line with the matching open character in the message window, with
! the open character highlighted.  Try to handle quotes by skipping over
! strings when encountered - doesn't work perfectly if already in a quoted
! strings.  Doesn't handle comments.

! Parameters:
!
!       match_chars             String - characters to be matched; e.g. "()"
!       quote_chars             String - quote characters; e.g. "'"""

procedure eveplus_match (match_chars, quote_chars)      ! Find the open paren

local this_position,            ! Marker - current cursor position
      right_matches,            ! Integer - number of opens to close
      all_chars,                ! String - match_chars + quote_chars
      match_pattern,            ! Pattern - any (all_chars)
      match_position,           ! Marker - current position during searches
      this_quote;               ! String - current quote character

    on_error
        ! Just continue
    endon_error;

    if length (match_chars) <> 2 then
        message ("Must have 2 characters to match");
        return;
    endif;

    copy_text (substr (match_chars, 2, 1));
    this_position := mark (none);
    right_matches := 1;
    move_horizontal (-1);
    all_chars := match_chars + quote_chars;
    match_pattern := any (all_chars);
    loop
        match_position := search (match_pattern, reverse);
        exitif match_position = 0;
        position (match_position);
        if index (quote_chars, current_character) > 0 then
            this_quote := current_character;
            move_horizontal (-1);           
            match_position := search (this_quote, reverse);
            exitif match_position = 0;
            position (match_position);
        else
            if current_character = substr (match_chars, 1, 1) then
                right_matches := right_matches - 1;
            else
                right_matches := right_matches + 1;
           endif;
        endif;
        exitif right_matches = 0;
    endloop;

    if right_matches = 0 then
        eveplus_display_line;
    else
        message ("No matching parentheses found");
    endif;

    position (this_position);

endprocedure;

! Internal routine for eveplus_match
! Display current line in message window, with current position highlighted

procedure eveplus_display_line          ! Display the matching line

local this_position,            ! Marker - current cursor position
      this_line,                ! String - current line
      start_of_line,            ! Marker - Start of current line
      this_offset;              ! Integer - offset of this_position

    this_position := mark (blink);
    this_offset := current_offset;
    move_horizontal (- current_offset);
    start_of_line := mark (none);
    move_horizontal (length (current_line));
    this_line := create_range (start_of_line, mark (none), none);
    message (this_line);
    position (end_of (message_buffer));
    move_vertical (-1);
    move_horizontal (this_offset);
    eveplus_this_position := mark (blink);
    position (this_position);

endprocedure;

procedure eve_set_flashing(arg)                 ! Turn on flashing parens
LOCAL   the_key,
        the_keys,
        key_number,
        ptr;

    eve$prompt_string(arg,
                      the_keys,
                     "Flash what characters: ",
                     "No flashing set");

    ptr := 1;
    loop
        exitif (ptr > length(the_keys));
        the_key := substr(the_keys, ptr, 1);
        key_number := index(eveplus_matchable_close, the_key);
        if (key_number <> 0) then
            define_key ("eveplus_match ('" 
                        + substr(eveplus_matchable_open, key_number, 1)
                        + the_key
                        + "', '""''')",
                        key_name (the_key),
                        " typing");
        else
            message('"' + the_key + '" is not matchable');
            return;
        endif;
        ptr := ptr + 1;  
    endloop;

endprocedure;

procedure eve_set_noflashing(arg)               ! Turn off falshing parens
LOCAL   the_key,
        the_keys,
        ptr;

    eve$prompt_string(arg,
               the_keys,
               "Remove flashing for what charcters: ",
               "No flashing characters removed");

    ptr := 1;
    loop
        exitif (ptr > length(the_keys));
        the_key := substr(the_keys, ptr, 1);
        if (index(eveplus_matchable_close, the_key) <> 0) then
            undefine_key(key_name(the_key));
        else
            if (index(eveplus_matchable_open, the_key) = 0) then
                message('"' + the_key + '" is not matchable');
                return;
            endif;
        endif;
        ptr := ptr + 1;
    endloop;

endprocedure;

procedure tpu$local_init                        ! Package initialization

    eve$arg1_set_matching := 'string';
    eve$arg1_set_nomatching := 'string';
    eve$arg1_set_flashing := 'string';
    eve$arg1_set_noflashing := 'string';
    eveplus_matchable_open := "([{<«'`"""; 
    eveplus_matchable_close  := ")]}>»''""";

endprocedure;

tpu$local_init;
