home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 5 Edit / 05-Edit.zip / p2demo21.exe / PEL / BOOKMARK.PEL < prev    next >
Text File  |  1995-03-17  |  20KB  |  816 lines

  1. # $Header:   P:\source\wmacros\bookmark.pev   1.42   17 Mar 1995 09:50:04   NOBLE  $
  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:   bookmark.pel  $: Support for Marked Blocks
  20.  
  21. ## $Tabs:4 7$
  22.  
  23. # global markid assignments
  24.  
  25. #local   MIN_BOOKMARK    = 1             # window/buffer/pos bookmarks
  26. #local   MAX_BOOKMARK    = 10
  27.  
  28. # selection types (constants):
  29.  
  30. global  NO_SELECTION            = 0
  31. global  NORMAL_SELECTION        = 1
  32. global  COLUMN_SELECTION        = 2
  33. global  LINE_SELECTION          = 3
  34. global  INCLUSIVE_SELECTION     = 4
  35.  
  36. local   MULTIPLE_SELECTION      = 1
  37. local   event_defined           = 0
  38.  
  39. ### system-wide bookmarks
  40.  
  41. global  TEMP_MARK       = 999           # generic temporary
  42.                                         # values above this are illegal
  43.  
  44. global bookmark_table      # bookmark_table[i].file - filename of bookmark "i"
  45.                            # bookmark_table[i].number - markid of bookmark "i"
  46.                            # bookmark_table[i].buff_id - buffer id of bookmark "i"
  47.  
  48. global function goto_bookmark( name )
  49. {
  50.    local num
  51.    local bookmarksInUse
  52.    local n = 0
  53.    local i
  54.    local filename;
  55.    local success = FALSE
  56.  
  57.    for ( i in bookmark_table )
  58.    {
  59.        n++
  60. #         bookmarksInUse = bookmarksInUse " " i
  61. #      else
  62. #         bookmarksInUse = num = i
  63.    }
  64.  
  65.    if ( n == 0 )
  66.    {
  67.       warning( "No bookmarks defined." )
  68.       return
  69.    }
  70.  
  71. #   if ( n >= 1 )
  72. #   {
  73. #      name = prompt_history(  "BOOKMARKS", "Enter bookmark to jump to [" \
  74. #                              bookmarksInUse "]: ", num )
  75. #   }
  76.  
  77.    if ( name == "" )
  78.       name = prompt_history("BOOKMARKS", "Enter bookmark to jump to : ", "", 0, 0, "goto_bookmark_prompt");
  79.  
  80.    if ( name in bookmark_table )
  81.    {
  82.       filename = bookmark_table[name].file;
  83.       if ( create_buf_and_win(filename) )
  84.       {
  85.          goto_mark(bookmark_table[name].number)
  86.          display_filename()
  87.          success = TRUE
  88.       }
  89.       else
  90.          warning( "Error: could not access file: %s", filename )
  91.    }
  92.    else
  93.       message( "Bookmark %s is undefined.", name )
  94.  
  95.    return success
  96. }
  97.  
  98. global function bookmark_defined(name)
  99. {
  100.    local rc = 0
  101.    local start_buff = current_buffer
  102.  
  103.    if (name in bookmark_table) 
  104.    {
  105.       current_buffer = bookmark_table[name].buff_id
  106.       rc = mark_defined(bookmark_table[name].number);
  107.    }
  108.  
  109.    current_buffer = start_buff
  110.    return rc;
  111. }
  112.  
  113. global function delete_bookmark(name)
  114.    local start_buff = current_buffer
  115.    
  116.    # delete old mark if one exists.
  117.    if (name in bookmark_table) 
  118.    {
  119.       current_buffer = bookmark_table[name].buff_id
  120.       delete_mark(bookmark_table[name].number);
  121.       delete(bookmark_table[name])
  122.    }
  123.    
  124.    current_buffer = start_buff
  125. }
  126.  
  127. # place a bookmark at the cursor (companion to goto_bookmark)
  128. #
  129. global function place_bookmark( name, noPrompt, system_mark )
  130. {
  131.    local i, num, mark = TRUE;
  132.    local max_name = 0;  # highest current mark name
  133.  
  134.    # If no argument was given, prompt for a bookmark name to
  135.    # use, offering the next numerically available bookmark as a default.
  136.  
  137.    if(name == "")
  138.    {
  139.       name = 0;
  140.       for(name in bookmark_table)
  141.          if (name+0 > max_name)
  142.             max_name = name+0
  143.             
  144.       max_name += 1;
  145.  
  146.       name = max_name "";
  147.       name = prompt_history("BOOKMARKS", "Bookmark name to drop: ", name, 1, 1, "place_bookmark_prompt")
  148.  
  149.       if(!name)
  150.          mark = FALSE;
  151.    }
  152.    else
  153.       add_prompt_history("BOOKMARKS", name)
  154.  
  155.    if(!noPrompt)
  156.    {
  157.       if( (name in bookmark_table) && 
  158.            (tolower(confirm("Reuse bookmark '" name "'? [yn]", "yYnN")) != "y"))
  159.       {
  160.          mark = FALSE;
  161.       }
  162.    }
  163.  
  164.    if(mark)
  165.    {
  166.       # delete old mark if one exists.
  167.       if (name in bookmark_table) 
  168.          delete_mark(bookmark_table[name].number);
  169.  
  170.       num = pick_unused_mark();
  171.       create_mark( num, current_line, current_column, TRUE );
  172.       bookmark_table[name].number = num;
  173.       bookmark_table[name].file   = buffer_filename;
  174.       bookmark_table[name].system = system_mark;
  175.       bookmark_table[name].buff_id = current_buffer;
  176.  
  177.       message( "Dropped bookmark %s", name )
  178.       display_update();
  179.  
  180.       # the next pointless looking line forces the line numbers to be redrawn
  181.       # which shows a bookmark marker immediately
  182.       linenumber_format = linenumber_format;
  183.       
  184.       if(!event_defined)
  185.       {
  186.          event_defined = TRUE;
  187.          attach_event_handler(EVENT.DELETING_BUFFER, function_id("buffer_delete_bookmarks"));
  188.       }
  189.    }
  190.  
  191.    return mark
  192. }
  193.  
  194. global function buffer_delete_bookmarks()
  195. {
  196.    local i;
  197.  
  198.    if(!and(buffer_flags, BUFFER_SYSTEM))
  199.       for(i in bookmark_table)
  200.          if(bookmark_table[i].buff_id == current_buffer)
  201.          {
  202.             delete_mark(bookmark_table[i].number)
  203.             delete bookmark_table[i];
  204.          }
  205. }
  206.  
  207. global function bookmark_delete_pressed(list_line, data_line)
  208. {
  209.    local mark, pos, msg, name, array, start_buff;
  210.  
  211.    start_buff = current_buffer;
  212.    
  213.    pos = match(list_line, ":");
  214.    name = substr(list_line, 1, pos-1);
  215.    split(data_line, array);
  216.  
  217.    if(name in bookmark_table)
  218.    {
  219.       edit_file(array[1]);
  220.       mark = bookmark_table[name].number;
  221.       delete_mark(mark);
  222.       delete bookmark_table[name];
  223.    }
  224.    else
  225.    {
  226.       # restore the deleted bookmark when the dialog is still visible
  227.       #  (the user pressed the Delete button twice)
  228.       edit_file(array[1]);
  229.       goto_pos(array[2], array[3]);
  230.       place_bookmark(name);
  231.    }
  232.    
  233.    current_buffer = start_buff;
  234.  
  235.    # this is that same goofy thing we have to do in place_bookmark to redraw line numbers.
  236.    linenumber_format = linenumber_format;
  237.    update_current_view();
  238. }
  239.  
  240. global function build_bookmark_list()
  241. {
  242.    local list[]
  243.    local name
  244.    local start_buff = current_buffer
  245.    local line, column, filename, mark, text;
  246.    
  247.    for(name in bookmark_table)
  248.       if ( !bookmark_table[name].system )
  249.          if(bookmark_table[name].buff_id)
  250.          {
  251.             current_buffer = bookmark_table[name].buff_id
  252.             mark   = bookmark_table[name].number;
  253.             line   = mark_line(mark);
  254.             column = mark_column(mark);
  255.             filename = bookmark_table[name].file;
  256.          
  257.             save_position();
  258.             goto_line(line);
  259.             goto_bol();
  260.             text = read_buffer();
  261.             restore_position(TRUE);
  262.          
  263.             list[name]   = name ": " filename " ( " line " , " column " ) : " text;
  264.          }
  265.          
  266.    current_buffer = start_buff
  267.    return list         
  268. }
  269.  
  270. global function bookmark_list()
  271. {
  272.    local dhList, line, column, filename, name, mark, data, text,
  273.          found = FALSE, start_buff;
  274.  
  275.    dhList = create_list_dialog( "Bookmark List", editor_helpfile, "bookmark_list_callback" );
  276.  
  277.    start_buff = current_buffer;
  278.  
  279.    for(name in bookmark_table)
  280.    {
  281.       if ( !bookmark_table[name].system )
  282.          if(bookmark_table[name].buff_id)
  283.          {
  284.             current_buffer = bookmark_table[name].buff_id
  285.             mark   = bookmark_table[name].number;
  286.             line   = mark_line(mark);
  287.             column = mark_column(mark);
  288.             filename = bookmark_table[name].file;
  289.          
  290.             save_position();
  291.             goto_line(line);
  292.             goto_bol();
  293.             text = read_buffer();
  294.             restore_position(TRUE);
  295.          
  296.             data   = name ": " filename " ( " line " , " column " ) : " text;
  297.          
  298.             add_item_to_list(dhList, data, filename, line, column, -1);
  299.             found = TRUE;
  300.          }
  301.    }
  302.    
  303.    current_buffer = start_buff;
  304.    
  305.    if(found)
  306.       begin_list_dialog(dhList);
  307.    else
  308.    {
  309.       delete_list_dialog(dhList);
  310.       warning("No bookmarks set");
  311.    }
  312. }
  313.  
  314. function write_block_key()
  315. {
  316.    local   fileToWrite
  317.    local   status
  318.  
  319.    if( selection_type() == NO_SELECTION )
  320.    {
  321.       if (buffer_filename)
  322.       {
  323.          if ( !and( buffer_flags, BUFFER_MODIFIED ) )
  324.             message( buffer_name ": has not been modified. " );
  325.          else if ( is_scratch_file(current_buffer)  )
  326.                write_buffer_as()
  327.          else
  328.          {
  329.             message( buffer_name ":" );
  330.             backup_file( buffer_filename );
  331.             status = write_buffer();
  332.             if ( (status >= 0) && (!errno) )
  333.                message( buffer_name ":" buffer_last_line " lines written" );
  334.          }
  335.       }
  336.       else
  337.          warning( "buffer_filename is not defined. " );
  338.    }
  339.    else
  340.    {
  341.       fileToWrite = prompt( "Write block as: ", "" )
  342.       if (fileToWrite)
  343.       {
  344.          backup_file( fileToWrite );
  345.          if (write_marked_block( fileToWrite ))
  346.             message("Write successful.")
  347.       }
  348.    }
  349. }
  350.  
  351. local function set_anchor_mark( mtype )
  352. {
  353.    local   otype = selection_type()
  354.  
  355.    if ( otype == mtype )
  356.    {
  357.       # There is a currently a selection of the specified type.
  358.       # If the selection is "floating" with the cursor as one
  359.       # endpoint, make the selection cursor independent if multiple
  360.       # selections are enabled.
  361.       # Otherwise remove the existing selection.
  362.       #
  363.       if ( ( selection_mode == MULTIPLE_SELECTION ) &&
  364.            (( selection_mark_top() == 0 ) || 
  365.             ( selection_mark_bottom() == 0 )) )
  366.          end_selection()
  367.       else if ( selection_mode == MULTIPLE_SELECTION )
  368.          begin_selection(mtype)
  369.       else
  370.          remove_selection()
  371.    }
  372.    else
  373.    {
  374.       # Create a new selection
  375.       #
  376.       remove_selection()
  377.       begin_selection( mtype )
  378.    }
  379. }
  380.  
  381.  
  382. global function set_exclusive_mark()
  383. {
  384.    set_anchor_mark( NORMAL_SELECTION );
  385. }
  386.  
  387. global function set_column_mark()
  388. {
  389.    set_anchor_mark( COLUMN_SELECTION );
  390. }
  391.  
  392. global function set_line_mark()
  393. {
  394.    set_anchor_mark( LINE_SELECTION );
  395. }
  396.  
  397. global function set_inclusive_mark()
  398. {
  399.    set_anchor_mark( INCLUSIVE_SELECTION );
  400. }
  401.  
  402. global function copy_to_scrap_key( append )
  403. {
  404.    local    status;
  405.       
  406.    if (argcount() && append)
  407.       status = append_to_scrap();
  408.    else
  409.       status = copy_to_scrap();
  410. }
  411.  
  412. #
  413. # mark_paragraph()
  414. #
  415. # mark the current paragraph by first searching backward to the
  416. # beginning of the paragraph (a blank line) and then searching forwards
  417. # to the end of the paragraph ( a blank line ).
  418. #
  419. global function mark_paragraph()                                #PUBLIC #INT
  420. {
  421.    # find beginning of paragraph
  422.    #
  423.    if ( !search("^[ \t]*$", SEARCH_BKWD_REGEX_MAX) )
  424.       goto_buffer_top();
  425.  
  426.    search("[ \t]*\\c[^ \t]", SEARCH_FWD_REGEX_MAX)
  427.  
  428.    begin_selection( NORMAL_SELECTION )
  429.  
  430.    # find end of paragraph
  431.    #
  432.    if ( !search("^[ \t]*$", SEARCH_FWD_REGEX_MAX) )
  433.       goto_buffer_bottom()
  434.  
  435.    end_selection()
  436. }
  437.  
  438. ## marked_region_size()
  439. #
  440. # Returns the number of characters included in the current highlight.
  441. # If the current selection is a column block, return the area.
  442. # (Note that column block may include virtual space, so the area may
  443. # differ from the number of characters in the highlight.)
  444. #
  445. global function marked_region_size()
  446. {
  447.    local st
  448.    local height, width
  449.    local begin
  450.    local markid
  451.    local ret
  452.  
  453.    # ensure that a highlight exists
  454.    st = selection_type()
  455.    if ( !st )
  456.       return 0
  457.  
  458.    save_position()
  459.  
  460.    # get the position at the top of the selected region
  461.    #
  462.    goto_mark( selection_mark_top() )
  463.    if ( st == COLUMN_SELECTION )
  464.    {
  465.       height  = current_line
  466.       width   = current_column
  467.    }
  468.    else
  469.    {
  470.       if ( st == LINE_SELECTION )
  471.          goto_bol()                 # include all of the first line
  472.  
  473.       begin = buffer_offset
  474.    }
  475.  
  476.    # get the position at the bottom of the selected region
  477.    #
  478.    markid = selection_mark_bottom()
  479.    if ( markid )
  480.       goto_mark( markid )
  481.    else
  482.    {
  483.       restore_position( 1 )
  484.       save_position()
  485.    }
  486.  
  487.    if ( st == COLUMN_SELECTION )
  488.    {
  489.       height = current_line - height + 1
  490.       width = ( width > current_column )              \
  491.                       ? width - current_column + 1    \
  492.                       : current_column - width + 1
  493.       ret = height * width         # area
  494.    }
  495.    else
  496.    {
  497.       if ( st == LINE_SELECTION )
  498.       {
  499.          goto_eol()      # include all of the last line
  500.          next_char()
  501.       }
  502.       else if ( st == INCLUSIVE_SELECTION )
  503.       {
  504.          # include character at cursor
  505.          next_char()
  506.       }
  507.       ret = buffer_offset - begin
  508.    }
  509.  
  510.    restore_position( 1 )
  511.    return ret
  512. }
  513.  
  514. #===========================================================================
  515. # primitives which extend the current selection
  516.  
  517. global function extend_selection_init()
  518. {
  519.    # make sure selection is active
  520.    if ( !selection_type() )
  521.       begin_selection( NORMAL_SELECTION )
  522. }
  523.  
  524. global function extend_selection()
  525. {
  526.    local   mark1, mark2
  527.    local   diff1, diff2
  528.  
  529.    # Get current selection endpoints
  530.    #
  531.    mark1 = selection_mark_top()
  532.    mark2 = selection_mark_bottom()
  533.    if ( !mark1 || !mark2 )
  534.    {
  535.       end_selection()
  536.       return
  537.    }
  538.  
  539.    # Find mark closest to cursor
  540.    #
  541.    diff1 = distance_between_marks( mark1, 0 )
  542.    diff2 = distance_between_marks( mark2, 0 )
  543.  
  544.    if ( diff1 < 0 )
  545.       diff1 = 0 - diff1
  546.    if ( diff2 < 0 )
  547.       diff2 = 0 - diff2
  548.  
  549.    # Move the closer mark to the current cursor position
  550.    #
  551.    create_mark( ((diff1 < diff2) ? mark1 : mark2) )
  552. }
  553.  
  554. #===========================================================================
  555.  
  556. # functions to save and restore the current selection (stack of 1)
  557. #
  558.  
  559. local   selectionArray
  560.  
  561. global function save_selection()
  562. {
  563.    selectionArray.type = selection_type()
  564.  
  565.    if ( selectionArray.type )
  566.    {
  567.       # Save the original cursor position.
  568.       #
  569.       selectionArray.curpos = create_mark( pick_unused_mark() )
  570.  
  571.       # Save the id numbers of the two bookmarks now in use, in
  572.       # case they are permanent bookmarks assigned by the user.
  573.       #
  574.       selectionArray.m1 = selection_mark_top()
  575.       selectionArray.m2 = selection_mark_bottom()
  576.       if ( !selectionArray.m1 )
  577.       {
  578.          selectionArray.m1 = selectionArray.m2
  579.          selectionArray.m2 = 0
  580.       }
  581.  
  582.       # Make copies of the two selection endpoints
  583.       #
  584.       goto_mark( selectionArray.m2 )
  585.       selectionArray.temp2 = create_mark( pick_unused_mark() )
  586.       goto_mark( selectionArray.m1 )
  587.       selectionArray.temp1 = create_mark( pick_unused_mark() )
  588.  
  589.       # Now it is safe to remove the selection.
  590.       remove_selection()
  591.  
  592.       # Return to the original cursor position
  593.       goto_mark( selectionArray.curpos )
  594.  
  595.       update_current_view()
  596.    }
  597. }
  598.  
  599. global function restore_selection()
  600. {
  601.    if ( selectionArray )
  602.    {
  603.       if ( selectionArray.type )
  604.       {
  605.          # restore the first endpoint
  606.          #
  607.          if ( !begin_selection( selectionArray.type, selectionArray.m1 ))
  608.          {
  609.             # m1 no longer exists, create a new one
  610.             begin_selection( selectionArray.type, selectionArray.temp1 )
  611.          }
  612.          else
  613.             delete_mark( selectionArray.temp1 )
  614.  
  615.          # Restore the second endpoint.
  616.          #
  617.          if ( selectionArray.m2 )
  618.          {
  619.             if ( !end_selection( selectionArray.m2 ))
  620.             {
  621.                # m2 no longer exists, create a new one
  622.                end_selection( selectionArray.temp2 )
  623.             }
  624.          }
  625.          else
  626.             delete_mark( selectionArray.temp2 )
  627.  
  628.          # Return the cursor to the original location.
  629.          goto_mark( selectionArray.curpos )
  630.          delete_mark( selectionArray.curpos )
  631.  
  632.          update_current_view()
  633.       }
  634.       delete( selectionArray )
  635.    }
  636. }
  637.  
  638. #===========================================================================
  639. #
  640. # The following functions are retained from SPE v1.1 for forward
  641. # compatibility.
  642. #
  643.  
  644. global function region_type()
  645. {
  646.    return selection_type()
  647. }
  648.  
  649. global function swap_selection_marks()
  650. {
  651.    swap_marks( selection_mark_top(), selection_mark_bottom() )
  652. }
  653.  
  654. local   anchorStack = initStack(anchorStack);
  655. local   selectionStack = initStack(selectionStack);
  656.  
  657. # CFV redesigned so that it matched the documentation from pel manuals
  658. # 9/24/93
  659. global function drop_anchor( type, mark1, mark2 )
  660. {
  661.    local retval = 0
  662. #  message("drop anchor: type = %d; mark1 = %d; mark2 = %d",type, mark1, mark2);
  663.    # save previous region type
  664.    selectionStack = pushStack( selectionStack, selection_type() )
  665.    
  666.    if ( argcount() == 0 )
  667.       type = NORMAL_SELECTION
  668.  
  669.    if ( argcount() == 3 )
  670.    {
  671.       if (mark_defined(mark1))
  672.       {
  673.          if (mark_defined(mark2))
  674.          {
  675.             goto_mark(mark1);
  676.             save_position();    # saves cursor postion of mark1
  677.             begin_selection( type, mark1 )
  678.             goto_mark(mark2);
  679.             return TRUE;
  680.          }
  681.          else 
  682.            return FALSE;
  683.       }
  684.       else 
  685.         return FALSE;
  686.     }
  687.  
  688.    save_position();   # save current cursor position
  689.    if ( argcount() == 2 )  {
  690.       if ( mark_defined(mark1) ) {
  691.          begin_selection( type, mark1 )
  692.          return TRUE;
  693.       }
  694.       else 
  695.          return FALSE
  696.    }
  697.    else {
  698.       begin_selection( type )
  699.       return TRUE
  700.    }
  701.  
  702. }
  703.  
  704. # CFV changed raise anchor so that it works like the manual says it should
  705. # 9/24/93
  706. global function raise_anchor()
  707. {
  708.    local mark1;
  709.    local cur_col = current_column;
  710.    local cur_line = current_line;
  711. #  local mark2 = create_mark( pick_unused_mark() );
  712.  
  713.    mark1 = restore_position( 0 );
  714. #  message("raise anchor");
  715.  
  716.    if ( mark1 )
  717.    {
  718. #  if (restore_position( 0 ) ) {
  719.  
  720.       mark1 = restore_position( 1 );
  721. #  warning("first restore pos = %d", mark1);
  722.       if ( mark1 )
  723.       {
  724. #     if ( restore_position( 1 ) ) {
  725.          save_position();
  726.  
  727.          begin_selection( topOfStack( selectionStack ) );
  728.          goto_pos(cur_line,cur_col);
  729.       }
  730.       else
  731.       {
  732.          remove_selection();
  733.       }
  734.       selectionStack = popStack( selectionStack );
  735.       return TRUE
  736.    }  # if mark1
  737.    else
  738.    {
  739. #  warning("removing selection")
  740.       remove_selection();
  741.       return FALSE
  742.    }
  743. }
  744.  
  745. # CFV changed so that it works like the manual says it should
  746. # 9/24/93
  747. global function toggle_anchor( type )
  748. {
  749.    if( selection_type() == NO_SELECTION )
  750.    {
  751.       if ( argcount() == 0 )
  752.          type = NORMAL_SELECTION
  753.  
  754.       drop_anchor( type )
  755.       return TRUE
  756.    }
  757.    else
  758.    {
  759.       raise_anchor()
  760.       return FALSE;
  761.    }
  762. }
  763.  
  764. local function initStack( stack )
  765. {
  766.    delete( stack )
  767.    stack[0] = 0;
  768.    return stack;
  769. }
  770.  
  771. local function pushStack( stack, element )
  772. {
  773.    local top = ++stack[0];
  774.  
  775.    stack[top] = element;
  776.    return stack;
  777. }
  778.  
  779. local function topOfStack( stack )
  780. {
  781.    local top = stack[0];
  782.    
  783.    if (top)
  784.    {
  785.       return stack[top];
  786.    }
  787.    else
  788.       return FALSE;
  789. }
  790.  
  791. local function popStack( stack )
  792. {
  793.    local top = stack[0];
  794.    local retval
  795.  
  796.    if (top)
  797.    {
  798.       delete(stack[top] );
  799.       --stack[0];
  800.       return stack;
  801.    }
  802. }
  803.  
  804. global function resetAnchorStacks()
  805. {
  806.    local i= 0;
  807.  
  808.    while (++i <= anchorStack[0])
  809.       delete_mark( anchorStack[i] );
  810.  
  811.    anchorStack = initStack( anchorStack );
  812.    selectionStack = initStack( selectionStack );
  813.    remove_selection();
  814. }
  815.