⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ed.c

📁 编辑器Tdedit3的源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
/*******************  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
 *
 * 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 "global.h"     /* global variables */
#include "prompts.h"    /* prompt assignments */
#include "default.h"    /* default function key assignments */


/*
 * 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( WINDOW *window )
{
char *source;           /* source for block move to make room for c */
char *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 WINDOW *win;   /* put window pointer in a register */
file_infos *file;       /* pointer to file structure in current window */
line_list_ptr new_node;
text_ptr new_line;      /* new line */

   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
    */
   new_node = (line_list_ptr)my_malloc( sizeof(line_list_struc), &rc );
   new_line = NULL;
   win->visible = FALSE;
   old_bcol = win->bcol;
   if (rc == OK) {
      new_node->line  = new_line;
      new_node->len   = 0;
      new_node->dirty = FALSE;

      if (win->ll->len != EOF) {
         win->file_info->modified = TRUE;
         if (mode.do_backups == TRUE)
            rc = backup_file( win );
         copy_line( win->ll );
         detab_linebuff( );
         len = g_status.line_buff_len;
         split_len = 0;
         if (win->rcol < len)
            win->ll->dirty = TRUE;

         source = g_status.line_buff + len;
         if (carriage_return || split_line) {
            if (win->rcol < len) {
               source = g_status.line_buff + win->rcol;
               split_len = len - win->rcol;
               len = win->rcol;
            }
         }
         g_status.line_buff_len = len;
         entab_linebuff( );
         if (un_copy_line( win->ll, win, 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;
            entab_linebuff( );
         } else
            rc = ERROR;
      } else {
         g_status.line_buff_len = len = 0;
         g_status.copied = TRUE;
      }

      if (rc == OK) {
         new_node->line  = new_line;
         new_node->len   = 0;
         new_node->dirty = TRUE;

         /*
          * 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) {
            win->ll->next->prev = new_node;
            new_node->next = win->ll->next;
            win->ll->next = new_node;
            new_node->prev = win->ll;
         } else {
            new_node->next = win->ll;
            if (win->ll->prev != NULL)
               win->ll->prev->next = new_node;
            new_node->prev = win->ll->prev;
            win->ll->prev = new_node;
            if (new_node->prev == NULL)
               win->file_info->line_list = new_node;
            win->ll = new_node;
         }

         ++file->length;
         detab_linebuff( );
         entab_linebuff( );
         rc = un_copy_line( new_node, win, FALSE );
         adjust_windows_cursor( win, 1 );

         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++;
            win->rline++;
            if (win->ll->next != NULL) {
               win->bin_offset += win->ll->len;
               win->ll = win->ll->next;
            }
            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 );

                  assert( add >= 0 );
                  assert( add < MAX_LINE_LENGTH );

                  copy_line( win->ll );
                  detab_linebuff( );
                  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;
                  entab_linebuff( );
                  rc = un_copy_line( win->ll, win, TRUE );
               } else
                  win->rcol = 0;
            }
            if (rc == OK  &&  split_line) {
               win->rline--;
               win->ll = win->ll->prev;
               if (win->cline > win->top_line + window->ruler)
                  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 {
         if (new_node != NULL)
            my_free( new_node );
      }
   } else {
      if (new_node != NULL)
         my_free( new_node );
      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 );
      restore_marked_block( win, 1 );
      show_size( win );
      show_avail_mem( );
      if (old_bcol != win->bcol) {
         make_ruler( win );
         show_ruler( win );
      }
   }
   return( rc );
}


/*
 * 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
 */
int  insert_overwrite( WINDOW *window )
{
char *source;           /* source for block move to make room for c */
char *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) */
register int rcol;
register WINDOW *win;  /* put window pointer in a register */
int  rc;

   win = window;
   if (win->ll->len == EOF || g_status.key_pressed >= 256)
      rc = OK;
   else {
      rcol = win->rcol;
      /*
       * first check we have room - the editor can not
       *  cope with lines wider than g_display.line_length
       */
      if (rcol >= g_display.line_length) {
         /*
          * cannot insert more characters
          */
         error( WARNING, win->bottom_line, ed2 );
         rc = ERROR;
      } else {
         copy_line( win->ll );
         detab_linebuff( );

         /*
          * 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)
            /*
             * inserted characters, or overwritten characters at the end of
             *  the line, are inserted.
             */
            add = 1;
         else
            /*
             *  and no extra space is required to overwrite existing characters
             */
            add = 0;

         /*
          * check that current line would not get too long.
          */
         if (len + pad + add >= g_display.line_length) {
            /*
             * no more room to add
             */
            error( WARNING, win->bottom_line, ed3 );
            rc = ERROR;
         } else {

            /*
             * make room for whatever needs to be inserted
             */
            if (pad > 0  || add > 0) {
               source = g_status.line_buff + rcol - pad;
               dest = source + pad + add;

               assert( len + pad - rcol >= 0 );
               assert( len + pad - rcol < MAX_LINE_LENGTH );

               memmove( dest, source, len + pad - rcol );

               /*
                * put in the required padding
                */

               assert( pad >= 0 );
               assert( pad < MAX_LINE_LENGTH );

               memset( source, ' ', pad );
            }
            g_status.line_buff[rcol] = (char)g_status.key_pressed;
            g_status.line_buff_len += pad + add;
            entab_linebuff( );

            /*
             * always increment the real column (rcol) then adjust the
             * logical and base column as needed.   show the changed line
             * in all but the LOCAL window.  In the LOCAL window, there are
             * two cases:  1) update the line, or 2) redraw the window if
             * cursor goes too far right.
             */
            win->file_info->dirty = NOT_LOCAL;
            win->ll->dirty = TRUE;
            show_changed_line( win );
            if (win->ccol < win->end_col) {
               show_curl_line( win );
               show_ruler_char( win );

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -