home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 5 Edit / 05-Edit.zip / p2demo21.exe / PEL / WP.PEL < prev    next >
Text File  |  1995-03-28  |  26KB  |  1,053 lines

  1. # $Header:   P:\source\wmacros\wp.pev   1.41   28 Mar 1995 12:51:12   pfhmlw0  $
  2.  
  3. ##############################################################################
  4. #
  5. #       Compuware Corporation
  6. #         31440 Northwestern Highway
  7. #           Farmington Hills, Michigan 48334-2564
  8. #
  9. #   This source code listing contains information that is
  10. #   proprietary to Compuware Corporation and may not be copied
  11. #   duplicated, translated, transmitted, stored, retrieved
  12. #   or in any manner or by any method conveyed or disclosed
  13. #   to a third party or parties without express written
  14. #   permission from Compuware Corporation.
  15. #
  16. #  
  17. ##############################################################################
  18.  
  19. #### $Workfile:   wp.pel  $:  word processing support
  20.  
  21. local ALT_KEY = 0x08 
  22.  
  23. #local wp_priorContextLeft
  24.  
  25. ### toggle word processing (word-wrap) mode for the current buffer
  26.  
  27. global function toggle_wp( on )                                 #PUBLIC #VOID
  28. {
  29.    if ( argcount() )
  30.       wp( on )
  31.    else
  32.       wp()
  33. }
  34.  
  35. global function wp( onOff, wrap_continuous, carry_comments )
  36. {
  37.    local wrap_str
  38.    local flow_str
  39.    local carry_str
  40.    local count = argcount()
  41.  
  42.    if ( count < 3 )
  43.    {
  44.       carry_comments = !and( buffer_flags, BUFFER_WP_CARRY_COMMENTS );
  45.  
  46.       if ( count < 2 )
  47.       {
  48.          wrap_continuous = !and( buffer_flags, BUFFER_WP_WRAP_CONTINUOUS );
  49.  
  50.          if ( count < 1 )
  51.             onOff = !and( buffer_flags, BUFFER_WP_ENABLED );
  52.          else
  53.             onOff = 0+onOff
  54.       }
  55.       else
  56.          wrap_continuous = wrap_continuous+0
  57.    }
  58.    else
  59.       carry_comments = carry_comments+0
  60.  
  61.    if ( onOff )
  62.    {
  63.       auto_indent_mode = 0;
  64.       buffer_flags = or( buffer_flags, BUFFER_WP_ENABLED )
  65.       wrap_str = "Word processing enabled"
  66.    
  67.       if ( wrap_continuous )
  68.       {
  69.          buffer_flags = or( buffer_flags, BUFFER_WP_WRAP_CONTINUOUS )
  70.          flow_str = "continuous wrapping"
  71.       }
  72.       else
  73.          buffer_flags = and( buffer_flags, not(BUFFER_WP_WRAP_CONTINUOUS) )
  74.    
  75.       if ( carry_comments )
  76.       {
  77.          buffer_flags = or( buffer_flags, BUFFER_WP_CARRY_COMMENTS )
  78.          carry_str = "carry-down comments"
  79.       }
  80.       else
  81.          buffer_flags = and( buffer_flags, not(BUFFER_WP_CARRY_COMMENTS) )
  82.  
  83.       if ( wrap_str )
  84.       {
  85.          if ( flow_str || carry_str )
  86.             wrap_str = wrap_str ", with "
  87.    
  88.          wrap_str = wrap_str flow_str
  89.    
  90.          if ( flow_str && carry_str )
  91.             wrap_str = wrap_str " and "
  92.    
  93.          wrap_str = wrap_str carry_str
  94.    
  95.          message( wrap_str )
  96.       }
  97.    }
  98.    else
  99.    {
  100.       buffer_flags = and( buffer_flags, not(BUFFER_WP_ENABLED ) )
  101.       buffer_flags = and( buffer_flags, not(BUFFER_WP_WRAP_CONTINUOUS) )
  102.       buffer_flags = and( buffer_flags, not(BUFFER_WP_CARRY_COMMENTS) )
  103.       message( "Word processing disabled." )
  104.    }
  105. }
  106.  
  107. ### column and tab-stop shifts left and right
  108.  
  109. local function next_non_white()
  110. {
  111.    local str = ""
  112.    local offset
  113.  
  114.    str = read_buffer()
  115.    offset = match( str, "[^ \t]" )
  116.  
  117.    if ( offset )
  118.       goto_buffer_offset( buffer_offset + offset - 1 )
  119.  
  120.    return( offset > 0 )
  121. }
  122.  
  123. # DWM  4/29/94
  124. # Note: this function outdents from the 
  125. # current cursor position to either the 
  126. # previous tab stop, the first non-white 
  127. # char before that tab stop, or the column
  128. # specified
  129. local function delete_to_prev_tab( boundary_column )
  130. {
  131.    local start
  132.    local end
  133.    local len
  134.  
  135.    if ( !argcount() || boundary_column > current_column )
  136.       boundary_column = 1
  137.  
  138.    # get the number of chars to the prev tab
  139.    start = buffer_offset
  140.    goto_prev_tab()
  141.    end = buffer_offset
  142.    
  143.    if ( current_column < boundary_column )
  144.    {
  145.       current_column = boundary_column
  146.       end            = buffer_offset
  147.    }
  148.  
  149.    # if there are non-white chars 
  150.    # before tab, move to last one 
  151.    len = length( trim( read_buffer(start-end) ) )
  152.    current_column += len
  153.    
  154.    # outdent by deleting the appropriate chars
  155.    delete_chars( start - end - len )
  156. }
  157.                
  158. global function outdent_lines()
  159. {                     
  160.    local selection[]
  161.    local startcol = 1
  162.    local line
  163.  
  164.    save_position()
  165.  
  166.    if ( selection_type() && current_column > 0 )
  167.    {
  168.       selection = get_selection_info()
  169.       remove_selection()
  170.       update_current_view()
  171.  
  172.       if ( selection.type == LINE_SELECTION )
  173.          startcol = 1
  174.       else
  175.          startcol = selection.startcol
  176.  
  177.       # loop through the lines selected
  178.       for ( line = selection.startline; line <= selection.endline; line++ )
  179.       {
  180.          goto_pos( line, startcol )
  181.  
  182.          if ( next_non_white() && current_column > startcol )
  183.             delete_to_prev_tab( startcol ) # don't delete past startcol
  184.       }
  185.       restore_selection_info( selection )
  186.    }
  187.    else
  188.    {
  189.       goto_pos( current_line, startcol )
  190.       if ( next_non_white() && current_column > startcol )
  191.          delete_to_prev_tab( startcol ) # don't delete past startcol
  192.    }
  193.    restore_position(1)
  194. }
  195.  
  196. global function indent_lines()
  197. {
  198.    local selection[]
  199.  
  200.    save_position()
  201.  
  202.    if ( selection_type() && current_column > 0 )
  203.    {
  204.       selection = get_selection_info()
  205.       end_selection()
  206.    }
  207.  
  208.    skip_whitespace()
  209.  
  210.    if ( and(buffer_flags, BUFFER_TABS_TO_SPACES) )
  211.       indent_columns( distance_next_tab )
  212.    else
  213.       indent_tabs()
  214.  
  215.    if ( selection.type && current_column > 0 )
  216.       restore_selection_info( selection )
  217.  
  218.    restore_position(TRUE)
  219. }
  220.  
  221. global function indent_tab_maybe()
  222. {
  223.    if ( selection_type() && current_column > 0 )
  224.       indent_lines()
  225.    else
  226.       insert_key()
  227. }
  228.  
  229. global function outdent_tab_maybe()
  230. {
  231.    if ( selection_type() && current_column > 0 )
  232.       outdent_lines()
  233.    else
  234.       goto_prev_tab() 
  235. }
  236.  
  237. global function indent_space_maybe()
  238. {
  239.    if( selection_type() && current_column > 0 )
  240.    {
  241.       if( and( keyboard_flags, ALT_KEY ))
  242.          outdent_columns()
  243.       else
  244.          indent_columns()
  245.    }
  246.    else
  247.       insert_key(32)
  248. }
  249.  
  250. global function outdent_space_maybe()
  251. {
  252.    if( selection_type() && current_column > 0 )
  253.       outdent_columns()
  254.    else
  255.       backspace()
  256. }
  257.  
  258. ### delete_word()
  259.  
  260. function delete_word( n )
  261. {
  262.    local srchstr = word_delimiter
  263.    local srchchar = read_buffer(1)
  264.  
  265.    begin_selection( NORMAL_SELECTION )
  266.  
  267.    if ( isspace(srchchar) ||
  268.         match( srchstr, quote_regex(srchchar) ) ||
  269.         and(buffer_flags, BUFFER_IN_VIRTUAL_SPACE) )
  270.       next_word( n, "<|$" )
  271.    else
  272.       next_word( n, ">|$" )
  273.  
  274.    delete_chars()
  275. }
  276. ### delete_word()
  277.  
  278. function delete_prev_word( n )
  279. {
  280.    local srchstr = word_delimiter
  281.    local srchchar
  282.    
  283.  
  284.    if (current_column == 1)
  285.    {
  286.       if ( current_line != 1 )
  287.       {
  288.          current_line = current_line - 1
  289.          goto_eol()
  290.          current_column = current_column + 1
  291.       }
  292.       else
  293.          return
  294.    }
  295.  
  296.    srchchar = read_buffer(-1)
  297.  
  298.    begin_selection( NORMAL_SELECTION )
  299.  
  300.    search_count = n+0
  301.  
  302.    if ( isspace(srchchar) ||
  303.         match( srchstr, quote_regex(srchchar) ) ||
  304.         and(buffer_flags, BUFFER_IN_VIRTUAL_SPACE) )
  305.       search("^|>", SEARCH_BKWD_REGEX )
  306.    else
  307.       search("^|<", SEARCH_BKWD_REGEX )
  308.  
  309.    delete_chars()
  310. }
  311.  
  312. ### sentence and paragraph motions:
  313.  
  314. local function s_forw( p, n )
  315. {
  316.    local old = search_count
  317.    local result
  318.  
  319.    search_count = n ? n : 1
  320.    result = search( p, SEARCH_FWD_REGEX_MAX + SEARCH_ADVANCE )
  321.    search_count = old
  322.    
  323.    return result
  324. }
  325.  
  326. local function s_back( p, n )
  327. {
  328.    local old = search_count, result;
  329.  
  330.    search_count = n ? n : 1
  331.    result = search( p, SEARCH_BKWD_REGEX_MAX + SEARCH_ADVANCE )
  332.    search_count = old
  333.  
  334.    return result;
  335. }
  336.  
  337. #global sentence_pattern = "[.!?]( |$)+\\c"
  338. #global sentence_pattern = "(\\.|!|\\?)[)\"'\\]]*(\t| |$|^)+\\c"
  339. global sentence_pattern = "(\\.|!|\\?|(^[ \t]*$))[)\"'\\]]*\\c([ \t]|$|^)+"
  340.  
  341. global paragraph_pattern = "^[ \t]*$|^\\.PP|^\\.LP"
  342.  
  343. global section_pattern = "^\\{" #}
  344. global section_end_pattern = "^\\}" #}
  345.  
  346. function line_empty()
  347. {
  348.    local result = TRUE
  349.    result = trim(read_line()) ? FALSE : TRUE
  350.    return result
  351. }
  352.  
  353. # Go to the first character of the next sentence or the next blank line.
  354. # Skips multiple blank lines.
  355. function next_sentence( n, patt )
  356. {  
  357.    local result = TRUE
  358.    
  359.    if (!patt)
  360.       patt = sentence_pattern
  361.       
  362.    if (!n)
  363.       n = 1
  364.       
  365.    if (line_empty())
  366.    {
  367.       # skip all blank lines
  368.       next_word(0, "[^ \t]")
  369.       n--
  370.    }
  371.    
  372.    while (n > 0)
  373.    {
  374.       n--
  375.       if (line_empty())
  376.          next_word()
  377.       else if (!(result = s_forw( patt )) )
  378.          break;
  379.       # The following will move forward to the beginning of the next word or
  380.       # the beginning of the next empty line.
  381.       else if (!line_empty())
  382.          next_word(0, "<|(^[ \t]*$)")
  383.    }
  384.    return  result
  385. }
  386.  
  387. # Go to the first character of the current or previous sentence or the previous blank line.
  388. # Skips multiple blank lines.
  389. function prev_sentence( n, patt )
  390. {
  391.    local moved = FALSE
  392.    local ch
  393.    local result = FALSE
  394.    local start_line = current_line
  395.    local start_empty = line_empty()
  396.  
  397.    if (!patt)
  398.       patt = sentence_pattern
  399.       
  400.    #  save initial position;
  401.    save_position();
  402.    
  403.    if (!n)
  404.       n = 1
  405.       
  406.    if (line_empty())
  407.    {
  408.       while(line_empty())
  409.          current_line--
  410.       goto_eol()
  411.       prev_word(0,"<|^")
  412.    }
  413.    else
  414.    {
  415.       #  move backward in buffer so we don't find the same sentence again.
  416.       prev_word(0,"<|$")
  417.       if (line_empty())
  418.       {
  419.          goto_bol()
  420.          n--
  421.          result = TRUE
  422.       }
  423.       else if (current_line != start_line)
  424.       {
  425.          prev_word(0, "<|^")
  426.          goto_eol()
  427.       }
  428.    }
  429.    
  430.    while (n > 0)
  431.    {
  432.       n--
  433.       if (line_empty())
  434.       {
  435.          prev_word()
  436.       }
  437.       
  438.       if (!(result = s_back( patt )))
  439.          break
  440.          
  441.       if (!n)   
  442.          next_word(0, "[^ \t]")
  443.       else if (line_empty())
  444.       {
  445.          n--
  446.          goto_bol()
  447.       }
  448.       else if (!line_empty())
  449.          prev_word(0,"<|^")
  450.    }
  451.    
  452.    #  go back to our old position if another sentence not found
  453.    restore_position(!result);
  454.    
  455.    return result
  456. }
  457.  
  458. function next_paragraph( n, patt )
  459. {  
  460.    local result
  461.    if (!patt)
  462.       patt = paragraph_pattern
  463.       
  464.    save_position()
  465.    while (line_empty() && current_line < buffer_last_line)
  466.       current_line++
  467.    result = s_forw( patt, n )  
  468.    restore_position(!result);
  469.    return result 
  470. }
  471.  
  472. function prev_paragraph( n, patt )
  473. {  
  474.    local result
  475.    if (!patt)
  476.       patt = paragraph_pattern
  477.       
  478.    save_position()
  479.    while (line_empty() && current_line > 1)
  480.       current_line--
  481.    result = s_back( patt, n )  
  482.    restore_position(!result);
  483.    return result 
  484. }
  485.  
  486. function next_section( n, patt )
  487. {    
  488.    if (!patt)
  489.       patt = section_pattern
  490.       
  491.    return s_forw( patt, n )    
  492. }
  493.  
  494. function prev_section( n, patt )
  495. {   
  496.    if (!patt)
  497.       patt = section_pattern
  498.       
  499.    return  s_back( patt, n )
  500. }
  501.  
  502. ## reverse case of characters a string, upper to lower and lower to upper
  503. #       non-alphabetic characters are unaffected
  504. #
  505. function toreverse( s )                                         #PUBLIC #STR
  506. {
  507.    local ch, r = ""
  508.    
  509.    while( s )
  510.    {
  511.       ch = substr( s, 1, 1 )
  512.       s = substr( s, 2 )
  513.       if( islower( ch ))
  514.          ch = toupper( ch )
  515.       else if( isupper( ch ))
  516.          ch = tolower( ch )
  517.       r = r ch
  518.    }
  519.    
  520.    return r
  521. }
  522.  
  523. ## alter case sense of ranges in the current buffer
  524. #       non-alphabetic characters are unaffected
  525. #
  526.  
  527. function upper()                                                #PUBLIC #VOID
  528. {
  529.    local ch
  530.    
  531.    rgetc_init()
  532.    
  533.    while(( ch = rgetc() ))
  534.    {
  535.       if( islower( ch ))
  536.       {
  537.          ch = toupper( ch )
  538.          rputc( ch )
  539.       }
  540.    }
  541.  
  542.    rgetc_done()
  543. }
  544.  
  545. function lower()                                                #PUBLIC #VOID
  546. {
  547.    local ch
  548.    
  549.    rgetc_init()
  550.    
  551.    while(( ch = rgetc() ))
  552.    {
  553.       if( isupper( ch ))
  554.       {
  555.          ch = tolower( ch )
  556.          rputc( ch )
  557.       }
  558.    }
  559.  
  560.    rgetc_done()
  561. }
  562.  
  563. function reverse()                                              #PUBLIC #VOID
  564. {
  565.    local ch
  566.    
  567.    rgetc_init()
  568.    
  569.    while(( ch = rgetc() ))
  570.    {
  571.       if( islower( ch ))
  572.       {
  573.          ch = toupper( ch )
  574.          rputc( ch )
  575.       }
  576.       else if( isupper( ch ))
  577.       {
  578.          ch = tolower( ch )
  579.          rputc( ch )
  580.       }
  581.    }
  582.  
  583.    rgetc_done()
  584. }
  585.  
  586. ## capitalize the first letter of each word in a selection
  587. #       if there is no selection, capitalize the first letter
  588. #       of the next word.  If the selection starts in the middle
  589. #       of a word, alas, the middle character gets capitalized.
  590.  
  591. function capitalize()                                           #PUBLIC #VOID
  592. {
  593.    local ch
  594.    
  595.    rgetc_init()
  596.  
  597.    while(( ch = rgetc()))
  598.    {
  599.       if( isalpha( ch ))
  600.       {
  601.          if( islower( ch ))
  602.             rputc( toupper( ch ))
  603.          if( !next_word( 1 ))
  604.             break
  605.       }
  606.    }
  607.  
  608.    rgetc_done()
  609. }
  610.  
  611. ## rgetc(), rputc( ch ), rgetc_init(), rgetc_done()
  612. #
  613. #  This collection of functions facilitates the sequential replacement
  614. #  of all characters within a selected region.  If no selection is active,
  615. #  operate on the single character under the cursor.
  616. #
  617. #  Normal usage:
  618. #
  619. #               rgetc_init()
  620. #               while (( ch = rgetc())
  621. #                       if ( P( ch ))
  622. #                               rputc( F( ch ))
  623. #               rgetc_done()
  624. #
  625. # Revision 1.14 of this file included a different implementation
  626. # that cut the selection to a second buffer, processed the entire
  627. # buffer and then reinserted the result.  I thought it would be simpler
  628. # and faster, but it turned out to be more complex, and rather slow.
  629. #
  630. local   rgetc_x0, rgetc_y0
  631. local   rgetc_x1, rgetc_y1
  632. local   rgetc_st, rgetc_columnar, rgetc_offset
  633.  
  634. local function rgetc()
  635. {
  636.    local   ch
  637.    local   pastEol
  638.    local   targetLine
  639.    
  640.    restore_position( 0 )   # pop previously saved
  641.  
  642.    # if column selection, wrap at end of current row
  643.    #
  644.    if ( rgetc_columnar )
  645.    {
  646.       while ( (pastEol = ( current_column >= rgetc_x1 )) ||
  647.               current_column < rgetc_x0 )
  648.       {
  649.          targetLine = current_line + pastEol
  650.          if ( !goto_pos( targetLine, rgetc_x0 ) || current_line != targetLine )
  651.          {
  652.             return ""
  653.          }
  654.          else if ( !and( buffer_flags, BUFFER_IN_VIRTUAL_SPACE )){
  655.             break
  656.          }
  657.          next_char()
  658.       }
  659.    }
  660.  
  661.    # test for past end of selection
  662.    if( buffer_offset >= rgetc_offset )
  663.       return ""
  664.  
  665.    ch = read_buffer( 1 )
  666.    save_position()
  667.    next_char()
  668.    if( !ch )
  669.         ch = "\n"
  670.  
  671.    return ch
  672. }
  673.  
  674. # replace the character in the buffer most recently returned by rgetc
  675. #
  676. local function rputc( ch )
  677. {
  678.    restore_position( 1 )
  679.    insert_string( ch )
  680.    delete_chars(1)
  681.    save_position()
  682. }
  683.  
  684. # initialize a collection of variables for rgetc()/rputc() usage.
  685. #       Places the cursor at the upper left corner, and saves the 
  686. #       original position on the save_position stack.
  687. #
  688. #       No selection => process a single character.
  689. #
  690. local function rgetc_init()
  691. {
  692.    local tmp
  693.  
  694.    save_position()         # original position of selection
  695.            
  696.    # if no region is marked we behave as if a single char is marked
  697.    #
  698.    rgetc_st = selection_type()
  699.    if ( rgetc_st == NO_SELECTION )
  700.    {
  701.       rgetc_x1 = current_column
  702.       rgetc_y1 = current_line
  703.       rgetc_x0 = rgetc_x1++
  704.       rgetc_y0 = rgetc_y1
  705.    }
  706.    else
  707.    {
  708.       # get and remember starting & ending marks & normalize
  709.       # their locations
  710.       #
  711.       end_selection()
  712.       goto_mark( selection_mark_top() )
  713.       rgetc_x0 = current_column
  714.       rgetc_y0 = current_line
  715.  
  716.       goto_mark( selection_mark_bottom() )
  717.       rgetc_x1 = current_column
  718.       rgetc_y1 = current_line
  719.  
  720.       # remove the selection
  721.       #
  722.       remove_selection()
  723.  
  724.       # per-selection-type fine-tuning
  725.       #       
  726.       rgetc_columnar = 0
  727.       if( rgetc_st == COLUMN_SELECTION )
  728.       {
  729.          rgetc_columnar = 1
  730.          if( rgetc_x1 < rgetc_x0 )
  731.          {
  732.             tmp = rgetc_x0
  733.             rgetc_x0 = rgetc_x1
  734.             rgetc_x1 = tmp
  735.          }
  736.          rgetc_x1++
  737.       }
  738.       else if( rgetc_st == INCLUSIVE_SELECTION )
  739.          rgetc_x1++
  740.  
  741.       else if( rgetc_st == LINE_SELECTION )
  742.       {
  743.          rgetc_x0 = rgetc_x1 = 1
  744.          rgetc_y1++
  745.       }
  746.    }
  747.  
  748.    # save first byte offset past selection
  749.    if ( rgetc_st == LINE_SELECTION && rgetc_y1 > buffer_last_line )
  750.       rgetc_offset = buffer_size
  751.    else
  752.    {
  753.       goto_pos( rgetc_y1, rgetc_x1 )
  754.       rgetc_offset = buffer_offset
  755.    }
  756.  
  757.    goto_pos( rgetc_y0, rgetc_x0 )
  758.    if ( and( buffer_flags, BUFFER_IN_VIRTUAL_SPACE ))
  759.       next_char()
  760.  
  761.    update_current_view()
  762.    # rgetc() expects to discard a previously saved position:
  763.    save_position()
  764. }
  765.  
  766. # clean up the save_position stack and restore the original cursor position
  767. #
  768. local function rgetc_done()
  769. {
  770.    # WGN 3/13/95 - Removed the following condition since the position is NOT
  771.    # restored only in the case of a normal selection.  This caused capitalize()
  772.    # to always end up on the word after the selection.
  773. #   if( rgetc_st == 1 )
  774. #   {
  775. #      restore_position( 0 )
  776. #      # (can be used to reselect marked region)
  777. #   }
  778.  
  779.    restore_position( 1 )
  780. }
  781.  
  782. ## get_region_as_string
  783. #
  784. # Read the characters in a region and return them as a string.
  785. # For columnar selections, the two parameters "sep" and "term"
  786. # specify a string to be used to separate each of the lines of
  787. # the selection and to terminate the last line of the selection,
  788. # respectively.  A suggestion for the values of these strings
  789. # is " " and "\n" or, alternatively, "\n" and "\n".
  790. #
  791. global function get_region_as_str(sep, term)
  792. {
  793.    local x0, y0, x1, y1
  794.    local str, st, len, line
  795.    local end   # buffer offset at end of selection.  Can't use columns if
  796.                # there are tabs in line.
  797.  
  798.    # if no region is marked we return a null string
  799.    st = selection_type()
  800.    if ( st == NO_SELECTION )
  801.       return ""
  802.  
  803.    save_position()
  804.  
  805.    #
  806.    # determine the extent of the marked block
  807.    #
  808.  
  809.    end_selection()
  810.    goto_mark( selection_mark_top() )
  811.    x0 = current_column
  812.    y0 = current_line
  813.  
  814.    goto_mark( selection_mark_bottom() )
  815.    x1 = current_column
  816.    y1 = current_line
  817.  
  818.    # we no longer need the selection
  819.    remove_selection()
  820.  
  821.    # adjust region coordinates depending on type
  822.    if (st == INCLUSIVE_SELECTION)
  823.       x1++
  824.    else if (st == LINE_SELECTION)
  825.    {
  826.       x0 = x1 = 1
  827.       y1++
  828.    }
  829.  
  830.    # read the characters in the selection
  831.    goto_pos(y0, x0)
  832.    line = current_line
  833.    if  (st == COLUMN_SELECTION)
  834.    {
  835.       # read characters in the selection, add separators, terminator
  836.       len = x1 - x0 + 1
  837.       for (str = ""; line <= y1; line++)
  838.       {
  839.          # next five lines added to get the actual number of characters
  840.          save_position()
  841.          current_column = x1
  842.          end = buffer_offset
  843.          restore_position(1)
  844.          len = end - buffer_offset + 1
  845.          str = str read_buffer(len) ((current_line < y1) ? sep : term)
  846.          current_column = x0
  847.          current_line++
  848.       }
  849.    }
  850.    else
  851.    {
  852.       # read the lines in the selection, add newlines
  853.       for (str = ""; line <= y1; line++)
  854.       {
  855.          if (current_line < y1)
  856.             str = str read_buffer() "\n"
  857.          else if (x1 > current_column)
  858.          {
  859.             #str = str read_buffer(x1 - current_column)
  860.             save_position()
  861.             current_column = x1
  862.             end = buffer_offset
  863.             restore_position(1)
  864.             str = str read_buffer(end - buffer_offset)
  865.          }
  866.          current_column = 1
  867.          current_line++
  868.       }
  869.    }
  870.  
  871.    # clean up
  872.    restore_position(1)
  873.  
  874.    return str
  875. }
  876.  
  877. ### auto indent mode: automatically indent newly-entered lines to match
  878. #       the leading whitespace on the previous non-blank line.
  879. #
  880. #       One key, normally Enter, causes auto-indent to occur.
  881. #       Another key, normally Control-Enter causes auto-indent to
  882. #       occur after a line is "opened".
  883. #       
  884. #       The automatically-indented line is initially composed of virtual
  885. #       space.  This means that consecutive lines that are indented but
  886. #       also left blank do not contain any superfluous characters.
  887.  
  888. #function ai( on )                                       #PUBLIC #VOID
  889. #{
  890. #   if (argcount())
  891. #      toggle_auto_indent( on )
  892. #   else
  893. #      toggle_auto_indent()
  894. #}
  895.  
  896. ## toggle auto-indent mode
  897. #       when enabled auto_indent_cr does auto-indenting;
  898. #       when disabled auto_indent_cr merely inserts a "\n".
  899. #
  900. # if selection is present it causes the mode to be set to its value
  901. #       rather than toggled
  902.  
  903. function toggle_auto_indent( on )                #PUBLIC #VOID
  904. {
  905.    local verbose = 0
  906.    
  907.    if( argcount() < 1 )
  908.    {
  909.       on = !auto_indent_mode
  910.       verbose = 1
  911.    }
  912.  
  913.    auto_indent_mode = on
  914.  
  915.    if(auto_indent_mode)
  916.       buffer_flags = and(buffer_flags, not(BUFFER_WP_ENABLED ))
  917.  
  918.    if( verbose )
  919.       message( on ? "Auto-indent enabled." : "Auto-indent disabled." )
  920. }
  921.  
  922. # open line and auto-indent
  923.  
  924. function auto_indent_nl()
  925. {
  926.    goto_eol()
  927.    auto_indent_cr()
  928. }
  929.  
  930. # insert a new line and auto-indent
  931.  
  932. function auto_indent_cr(first_one)
  933. {
  934.    if( auto_indent_mode )
  935.       insert_auto_indent()
  936.    else 
  937.       insert_newline()
  938. }
  939.  
  940. # this function turns off real_space_only.  it then cuts the text from the
  941. # current cursor position and places it on the next line based on the spacing
  942. # of the previous line
  943. function insert_auto_indent(first_one)
  944. {
  945.    # check to see if real space is on
  946.    local real_space = and(buffer_flags, BUFFER_REAL_SPACE_ONLY)
  947.    local overtype   = and(buffer_flags, BUFFER_OVERTYPE_MODE)
  948.    local line, trailing, indent, col, follow, ret, ch
  949.  
  950.    # turn off real space so we can move around more freely
  951.    buffer_flags = and( buffer_flags, not(BUFFER_REAL_SPACE_ONLY))
  952.  
  953.    # if first_one is not passed, determine if this function was the last
  954.    # one called, added the = on current_line_offset <=... to fix a bug
  955.    # with expanding templates
  956.    if (!argcount())
  957.       first_one = (prev_command != current_command) || \
  958.                   (current_line_offset <= current_line_length)
  959.    if( first_one || overtype)
  960.    {
  961.       # THEN this is the first auto-indent of a possible sequence.
  962.       # We insert a newline and figure out if there's trailing
  963.       # text which needs to be indented.  If so we have to copy
  964.       # indented text; else we just position the cursor in virtual
  965.       # space on the new blank line.
  966.  
  967.       if (!overtype)
  968.       {
  969.          follow = read_buffer()
  970.          delete_to_eol()
  971.       }
  972.  
  973.       ret = insert_newline()
  974.  
  975.       if (current_column >= 1)
  976.       {
  977.          line     = current_line
  978.          trailing = ( current_line_offset < current_line_length )
  979.  
  980.          if (overtype)
  981.          {
  982.             if ((ch = read_buffer(1)))
  983.             {
  984.                # find indent of this line:
  985.                while (ch == " " || ch == "\t")
  986.                {
  987.                   next_char()
  988.                   ch = read_buffer(1)
  989.                }
  990.             }
  991.             else
  992.             {
  993.                # or last non-blank line:
  994.                do {
  995.                   prev_line()
  996.                } while( current_line > 1 && !read_buffer( 1 ))
  997.             }
  998.          }
  999.          else
  1000.          {
  1001.             # find indent of last non-blank line:
  1002.             do {
  1003.                prev_line()
  1004.             } while( current_line > 1 && !read_buffer( 1 ))
  1005.          }
  1006.  
  1007.          col = current_column
  1008.          goto_pos( line, col )
  1009.  
  1010.          if (length(follow))
  1011.          {
  1012.             # copy indent whitespace if there is trailing text:
  1013.             insert_string( follow )
  1014.             goto_pos( line, col )
  1015.          }
  1016.       }
  1017.    }
  1018.    else
  1019.    {
  1020.       # ELSE this is another in a sequence of consecutive 
  1021.       # auto-indent commands.  Thus we know that current_column
  1022.       # reflects the proper indentation; all we need to do is
  1023.       # insert a blank line before the current one and restore
  1024.       # cursor position on the newly positioned line.
  1025.  
  1026.       col = current_column
  1027.       ret = insert_newline()
  1028.  
  1029.       if (current_column >= 1)
  1030.           current_column = col
  1031.    }
  1032.  
  1033.    # restore what we may have turned off up above
  1034.    if ( real_space )
  1035.       buffer_flags = or( buffer_flags, BUFFER_REAL_SPACE_ONLY )
  1036.  
  1037.    return ret
  1038. }
  1039.  
  1040. # # insert and auto-indent a newline before the current line
  1041. # function auto_indent_before(){
  1042. #        if( current_line == 1 ){ 
  1043. #                goto_bol()
  1044. #                insert_newline_ai()
  1045. #                up()
  1046. #        } else {
  1047. #                up()
  1048. #                auto_indent_nl()
  1049. #        }
  1050. # }
  1051.         
  1052.