/**************************************************************************** * * File : killfix.e * Date Created : 7/22/96 * Description : updated line cut/copy/paste routines for v7 and v8 * * Programmer(s) : Morgwn McCarty * Last Modification : * Additional Notes : compile and load this extension to fix the way * Epsilon handles the cutting and pasting of line * regions * ****************************************************************************/ // Updated by Lugaru 1/26/97: // Yanking rectangular regions failed -- replaced call to rect_retrieve() // with a call to xfer_rectangle() which replaced it in v7.0. // We now include a slightly modified version of the pop_retrieve() // function to make yank-pop of rectangles work. /* updates and fixes include: when pasting a line region, the first line gets inserted at the _beginning_ of the line, regardless of where the cursor happens to be on that line. also, the cursor column gets restored. if you cut or copy lines, and either point or mark is on the last line of the buffer, epsilon would not paste the line region correctly (IMO). this has been fixed. if you cut or copy and no region is highlighted, the current line gets cut or copied--not the invisible region between point and mark. when pasting, the pasted region "flashes" for a moment. this is controlled by the "paste_flash_duration" variable. (set to 0 for no flash at all) if user variable "reindent_when_pasting_code" is set, pasted line regions will get re-indented when in c-mode. also, any comment that starts to the right of "comment_column" will get re-aligned. some people might want this stuff turned off. setting "rectangle_paste_leaves_cursor_at_end" will force a rectangle paste to leave the cursor at the bottom right corner of the region. this seemed a little more intuitive. Morgwn McCarty (morgwn@cs.uoregon.edu) PO Box 3681 Eugene, OR 97403 */ // some portions resemble code from Lugaru's kill.e, so... /************************************************************************ * "Epsilon" is a registered trademark licensed to Lugaru Software, Ltd. * * "EEL" and "Lugaru" are trademarks of Lugaru Software, Ltd. * * * * Copyright (C) 1985, 1995 Lugaru Software Ltd. All rights reserved. * * * * Limited permission is hereby granted to reproduce and modify this * * copyrighted material provided that the resulting code is used only in * * conjunction with Lugaru products and that this notice is retained in * * any such reproduction or modification. * ************************************************************************/ #include "eel.h" #include "kill.h" user int paste_flash_duration = 35; user int reindent_when_pasting_code = 1; user int rectangle_paste_leaves_cursor_at_end = 1; command kill_region_fix() on reg_tab[CTRL('W')] { do_copy_region(1); } command copy_region_fix() on reg_tab[ALT('w')] { do_copy_region(0); } do_copy_region(with_cut) int with_cut; { int orig_point; // save point int orig_col; // and save column int pos1; // beginning of region int pos2; // end of region int at_end_of_buffer; // flag // if we're not doing a line region, call standard epsilon functions // (...if there is no highlighting going on, fall through // and cut or copy the current line as a line region) if (is_highlight_on() && (region_type() != REGLINE)) { if (with_cut) { kill_region(); } else { copy_region(); } return; } // save original point and column orig_point = point; orig_col = virtual_column(); // normalize region if (is_highlight_on()) { // multiple lines if (point < mark) { pos1 = point; pos2 = mark; } else { pos1 = mark; pos2 = point; } } else { // force single line if no highlighting pos1 = pos2 = point; } // find beginning of first line point = pos1; to_begin_line(); pos1 = point; // find end of last line point = pos2; nl_forward(); pos2 = point; at_end_of_buffer = (current_column() != 0); // we're at end of buffer! // perform the cut or copy if (with_cut) { check_modify(bufnum); do_save_kill(pos1, pos2); } else { prev_cmd = 0; do_save_only(pos1, pos2); this_cmd = 0; highlight_off(); } // append a return if we are copying from the end of the buffer if (at_end_of_buffer) { buffer_printf(_cur_kill_buf, "\n"); } // set this kill buffer flag to "line-mode" _kill_width[_num_kill] = -2; // restore row and column if (with_cut) { point = pos1; to_virtual_column(orig_col); } else { point = orig_point; } } pop_retrieve() /* get previous kill buffer */ { int from, to, t, ok = 0, i = 0; spot before, after; from = point, to = mark; if (to < from) /* ensure from <= to */ from = mark, to = point; undo_flag = UNDO_FLAG_RETR; if (from != _oldfrom || to != _oldto) return 0; do { /* undo previous yank */ t = undo_op(1); if ((t & UNDO_FLAG) && undo_flag == UNDO_FLAG_KILL) { ok = 1 + (_kill_width[_num_kill] == REGION); break; /* found prev yank */ } } while (t && !(t & UNDO_END) && i++ < 10); if (ok == 2) { /* if region */ before = alloc_spot(0); /* remember where it was */ after = alloc_spot(1); } if (ok != 1) { /* unless rectangle, redo it now */ while (!(undo_op(0) & UNDO_FLAG) || undo_flag != UNDO_FLAG_RETR) ; /* redo it */ } if (ok == 2) { delete(*before, *after); free_spot(before); free_spot(after); } else if (!ok) return 0; t = _num_kill; do { /* get the previous kill buffer */ pop_kill(); /* skipping unused kbufs */ } while (_kill_width[_num_kill] == UNUSED && t != _num_kill); return 1; } int _oldfrom = -1, _oldto = -1; /* region yanked last time */ #define UNDO_FLAG_KILL 1 /* bracket each yank in undo with these */ #define UNDO_FLAG_RETR 2 /* for yank-pop */ retrieve(withpop) { char *thisbuf; int orig_col; int overwrite = over_mode; // about to modify buffer, maybe give error check_modify(bufnum); // ignore yanking to kill buffer thisbuf = bufname; if (thisbuf == _cur_kill_buf) return; // quit if no kill buffers used check_num_kill_buffers(); if (_kill_width[_num_kill] == UNUSED) return; // save column orig_col = virtual_column(); // zap last yanked region now if we're doing "yank-pop" if (withpop && !pop_retrieve()) error("Must follow yank or yank-pop"); // set header for undo stuff undo_flag = UNDO_FLAG_KILL; // yank the new region switch (_kill_width[_num_kill]) { // normal region case REGION: _oldfrom = point; bufname = _cur_kill_buf; xfer(thisbuf, 0, size()); bufname = thisbuf; flash_region(REGNORM); _oldto = point; break; // lines case -2: to_begin_line(); _oldfrom = point; bufname = _cur_kill_buf; xfer(thisbuf, 0, size()); bufname = thisbuf; if (reindent_when_pasting_code && // maybe re-align code (*major_mode == 'C')) reindent_code(); flash_region(REGNORM); to_virtual_column(orig_col); _oldto = point; break; // rectangle default: _oldfrom = point; bufname = _cur_kill_buf; #if 0 // Rect_retrieve is no longer defined in v7 and later. rect_retrieve(thisbuf); #else xfer_rectangle(name_to_bufnum(thisbuf), _kill_width[_num_kill], overwrite); #endif if (rectangle_paste_leaves_cursor_at_end) { point = mark; _oldto = mark; mark = _oldfrom; flash_region(REGRECT); } else { point = _oldfrom; flash_region(REGRECT); _oldto = mark; } break; } // make epsilon rebuild all of screen build_first = 1; } flash_region(region_type) { TIMER ts; // bail out if user doesn't want flash if (!paste_flash_duration) return; // highlight the region modify_region(1, MRTYPE, region_type); _highlight_control = 1; refresh(); // wait for a bit time_begin(&ts, paste_flash_duration); while ((!time_done(&ts)) && (!char_avail())) ; // turn off highlighting and refresh screen _highlight_control = 0; refresh(); } reindent_code() { int pos1; save_spot point, mark; // this is pretty rudimentary code, so I don't expect // it to work correctly in all cases or you might // want to tweak it to work right for you -mm // first, run normal indent region command indent_region(); // make point come before mark fix_region(); // make point beginning of first line // and make mark end of last line pos1 = point; point = mark; to_end_line(); point = pos1; to_begin_line(); // find all comments within block that begin // to the right of "comment_start" and re-align // them for ( ; ; ) { // search for comment, bail out if // we end up past end of region if (!re_search(RE_FORWARD, comment_start)) break; if (point >= mark) break; // re-indent comment point = matchstart; if ( current_column() > comment_column ) indent_for_comment(); nl_forward(); } }