📄 ed.c
字号:
/******************* start of original comments ********************//* * Written by Douglas Thomson (1989/1990) * * This source code is released into the public domain. *//* * Name: dte - Doug's Text Editor program - main editor module * Purpose: This file contains the main editor module, and a number of the * smaller miscellaneous editing commands. * It also contains the code for dispatching commands. * File: ed.c * Author: Douglas Thomson * System: this file is intended to be system-independent * Date: October 1, 1989 * I/O: file being edited * files read or written * user commands and prompts * Notes: see the file "dte.doc" for general program documentation *//********************* end of original comments ********************//* * The basic editor routines have been EXTENSIVELY rewritten. I have added * support for lines longer than 80 columns and I have added line number * support. I like to know the real line number that editor functions are * working on and I like to know the total number of lines in a file. * * I rewrote the big series of ifs in the dispatch subroutine. It is now * an array of pointers to functions. We know what function to call as soon * as a key is pressed. It is also makes it easier to implement a configuration * utility and macros. * * I added a few functions that I use quite often and I deleted a few that I * rarely use. Added are Split Line, Join Line, and Duplicate Line. Deleted * are Goto Marker 0-9 (others?). * * ************ In TDE 1.3, I put Goto Marker 0-9 back in. *************** * * I felt that the insert routine should be separated into two routines. One * for inserting the various combinations of newlines and one for inserting * ASCII and extended ASCII characters. * * One of Doug's design considerations was keeping screen updates to a minimum. * I have expanded upon that idea and added support for updating windows * LOCALly, GLOBALly, or NOT_LOCALly. For example, scrolling in one window * does not affect the text in another window - LOCAL update. Adding, deleting, * or modifying text in one window may affect text in other windows - GLOBAL * update. Sometimes, updates to the current window are handled in the task * routines so updates to other windows are done NOT_LOCALly. * * In version 2.2, the big text buffer scheme was replaced by a double * linked list. * * New editor name: TDE, the Thomson-Davis Editor. * Author: Frank Davis * Date: June 5, 1991, version 1.0 * Date: July 29, 1991, version 1.1 * Date: October 5, 1991, version 1.2 * Date: January 20, 1992, version 1.3 * Date: February 17, 1992, version 1.4 * Date: April 1, 1992, version 1.5 * Date: June 5, 1992, version 2.0 * Date: October 31, 1992, version 2.1 * Date: April 1, 1993, version 2.2 * Date: June 5, 1993, version 3.0 * Date: August 29, 1993, version 3.1 * Date: November 13, 1993, version 3.2 * Date: June 5, 1994, version 4.0 * Date: December 5, 1998, version 5.0 (jmh) * * This modification of Douglas Thomson's code is released into the * public domain, Frank Davis. You may distribute it freely. */#include "tdestr.h" /* typedefs for global variables */#include "define.h" /* editor function defs */#include "tdefunc.h" /* prototypes for all functions in tde */#include "common.h"#if !defined( __DOS16__ )#include <setjmp.h>jmp_buf editor_jmp;#endif#if defined( __WIN32__ )extern int handle_mouse; /* defined in win32/console.c */extern HANDLE conin;#endifextern long found_rline; /* defined in findrep.c *//* * Name: insert_newline * Purpose: insert a newline * Date: June 5, 1991 * Passed: window: pointer to current window * Notes: There a several ways to insert a line into a file: 1) pressing * a key, 2) word wrap, 3) any others? * When doing word wrap or format paragraph, don't show any changes. * Wait until the function finishes then show all changes at once. */int insert_newline( TDE_WIN *window ){text_ptr source; /* source for block move to make room for c */text_ptr dest; /* destination for block move */int len; /* length of current line */int split_len;int add; /* characters to be added (usually 1 in insert mode) */int rcol;int rc;long length;int carriage_return;int split_line;int wordwrap;int dirty;int old_bcol;register TDE_WIN *win; /* put window pointer in a register */file_infos *file; /* pointer to file structure in current window */line_list_ptr new_node; rc = OK; win = window; file = win->file_info; length = file->length; wordwrap = mode.word_wrap; switch (g_status.command) { case WordWrap : carriage_return = TRUE; split_line = FALSE; break; case AddLine : split_line = carriage_return = FALSE; break; case SplitLine : split_line = carriage_return = TRUE; break; case Rturn : default : /* * if file is opened in BINARY mode, lets keep the user from * unintentially inserting a line feed into the text. */ if (file->crlf == BINARY) return( next_line( win ) ); show_ruler_char( win ); carriage_return = TRUE; split_line = FALSE; break; } /* * make window temporarily invisible to the un_copy_line function */ win->visible = FALSE; old_bcol = win->bcol; new_node = new_line( DIRTY, &rc ); if (rc == OK) { if (win->ll->len != EOF) { file->modified = TRUE; if (mode.do_backups == TRUE) rc = backup_file( win ); copy_line( win->ll, win, TRUE ); len = g_status.line_buff_len; split_len = 0; /* jmh - added the AddLine test, since the current line is unchanged */ if (win->rcol < len && g_status.command != AddLine) win->ll->type |= DIRTY; if (carriage_return || split_line) { if (win->rcol < len) { split_len = len - win->rcol; len = win->rcol; } } source = g_status.line_buff + len; g_status.line_buff_len = len; if (un_copy_line( win->ll, win, TRUE, TRUE ) == OK) { assert( split_len >= 0 ); assert( split_len < MAX_LINE_LENGTH ); memmove( g_status.line_buff, source, split_len ); g_status.line_buff_len = len = split_len; g_status.copied = TRUE; } else rc = ERROR; } else { g_status.line_buff_len = len = 0; g_status.copied = TRUE; } if (rc == OK) { /* * we are somewhere in the list and we need to insert the new node. * if we are anywhere except the EOF node, insert the new node * after the current node. if the current node is the EOF node, * insert the new node before the EOF node. this keeps the * EOF node at the end of the list. */ if (win->ll->next == NULL) { insert_node( file, win->ll, new_node ); win->ll = new_node; } else insert_node( file, win->ll, new_node ); rc = un_copy_line( new_node, win, FALSE, TRUE ); adjust_windows_cursor( win, 1 ); restore_marked_block( win, 1 ); if (win->ll->len != EOF && file->syntax != NULL) syntax_check( win->ll, file->syntax->info ); syntax_check_lines( new_node, file->syntax ); if (file->dirty != GLOBAL) file->dirty = NOT_LOCAL; if (length == 0l || wordwrap || win->cline == win->bottom_line) file->dirty = GLOBAL; else if (!split_line) update_line( win ); /* * If the cursor is to move down to the next line, then update * the line and column appropriately. */ if (rc == OK && (carriage_return || split_line)) { dirty = file->dirty; if (win->cline < win->bottom_line) win->cline++; inc_line( win, TRUE ); rcol = win->rcol; old_bcol = win->bcol; if (win->ll->next != NULL) { if (mode.indent || wordwrap) { /* * autoindentation is required. Match the indentation of * the first line above that is not blank. */ add = find_left_margin( wordwrap == FIXED_WRAP ? win->ll : win->ll->prev, wordwrap, file->inflate_tabs, file->ptab_size ); assert( add >= 0 ); assert( add < MAX_LINE_LENGTH ); copy_line( win->ll, win, TRUE ); len = g_status.line_buff_len; source = g_status.line_buff; if (len + add > MAX_LINE_LENGTH) add = MAX_LINE_LENGTH - len; dest = source + add; assert( len >= 0); assert( len < MAX_LINE_LENGTH ); memmove( dest, source, len ); /* * now put in the autoindent characters */ assert( add >= 0 ); assert( add < MAX_LINE_LENGTH ); memset( source, ' ', add ); win->rcol = add; g_status.line_buff_len += add; shift_block( file, win->rline, 0, add ); rc = un_copy_line( win->ll, win, TRUE, TRUE ); } else win->rcol = 0; } if (rc == OK && split_line) { win->rline--; win->ll = win->ll->prev; if (win->cline > win->top_line) win->cline--; win->rcol = rcol; } check_virtual_col( win, win->rcol, win->ccol ); if (dirty == GLOBAL || file->dirty == LOCAL || wordwrap) file->dirty = GLOBAL; else file->dirty = dirty; } } else my_free( new_node ); } else error( WARNING, window->bottom_line, main4 ); /* * record that file has been modified */ win->visible = TRUE; if (rc == OK) { if (file->dirty != GLOBAL) my_scroll_down( win ); show_size( win ); show_avail_mem( ); if (old_bcol != win->bcol) show_ruler( win ); } return( rc );}/* * Name: adjust_for_tabs * Purpose: handle tabs in the line buffer in an appropriate manner * Date: May 24, 1998 (jmh) * Passed: rcol: pointer to current (real) column * inflate_tabs: are tabs being expanded? * tab_size: size of tab expansion * Returns: rcol adjusted if needed * Notes: If tabs are deflated or inflated, call detab_linebuff(), but if * real tabs are in use and it's insert mode, then leave the tabs * alone and adjust rcol. However, if we're in a tab, insert spaces * before it. * jmh 981129: must be updating the cursor in the normal direction. * jmh 991010: if it's not normal direction, it's overwrite mode. */static void adjust_for_tabs( int *rcol, int inflate_tabs, int tab_size ){int col;int len;int pad;text_ptr source;text_ptr dest; if (inflate_tabs == 2 && mode.insert) { len = g_status.line_buff_len; col = *rcol; *rcol = entab_adjust_rcol( g_status.line_buff, len, col, tab_size ); pad = col - detab_adjust_rcol( g_status.line_buff, *rcol, tab_size ); if (*rcol < len && g_status.line_buff[*rcol] == '\t') { if (pad > 0 && len + pad < MAX_LINE_LENGTH) { source = g_status.line_buff + *rcol; dest = source + pad; memmove( dest, source, len - *rcol ); memset( source, ' ', pad ); g_status.line_buff_len += pad; *rcol += pad; } } else if (*rcol == len) *rcol += pad; } else detab_linebuff( inflate_tabs, tab_size );}/* * Name: insert_overwrite * Purpose: To make the necessary changes after the user has typed a normal * printable character * Date: June 5, 1991 * Passed: window: pointer to current window * * jmh 980524: use a "real tabs" mode. If insert is on, don't detab the line. * jmh 981129: added the ability to update the cursor in different directions, * however, it always functions in overwrite mode (which is * assumed to be on). * jmh 020913: tab character in tab mode will use tab_key() with fixed tabs; * will probably cause problems in overwrite mode, but overwriting * tab characters should be done in deflate mode, anyway. */int insert_overwrite( TDE_WIN *window ){text_ptr source; /* source for block move to make room for c */text_ptr dest; /* destination for block move */int len; /* length of current line */int pad; /* padding to add if cursor beyond end of line */int add; /* characters to be added (usually 1 in insert mode) */int rcol;register TDE_WIN *win; /* put window pointer in a register */int rc = OK;int dir = mode.cur_dir; /* direction to update cursor */ win = window; if (win->ll->len != EOF && g_status.key_pressed < 256) { rcol = win->rcol; /* * first check we have room - the editor can not * cope with lines wider than MAX_LINE_LENGTH */ if (rcol >= MAX_LINE_LENGTH) { /* * cannot insert more characters */ error( WARNING, win->bottom_line, ed2 ); rc = ERROR; } else if (g_status.key_pressed == '\t' && win->file_info->inflate_tabs) { add = mode.smart_tab; mode.smart_tab = FALSE; rc = tab_key( win ); mode.smart_tab = add; } else { copy_line( win->ll, window, FALSE ); adjust_for_tabs( &rcol, win->file_info->inflate_tabs, win->file_info->ptab_size ); /* * work out how many characters need to be inserted */ len = g_status.line_buff_len; pad = rcol > len ? rcol - len : 0; if (mode.insert || rcol >= len || (dir == CUR_LEFT && rcol == 0)) { /* * inserted characters, or overwritten characters at the end of * the line, are inserted. */ add = 1; if (dir == CUR_LEFT && len == 0) ++add; } else /* * and no extra space is required to overwrite existing characters */ add = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -