📄 textbuf.c
字号:
static const char CVSID[] = "$Id: textBuf.c,v 1.28.2.1 2003/06/18 09:54:49 edg Exp $";/******************************************************************************** ** textBuf.c - Manage source text for one or more text areas ** ** Copyright (C) 1999 Mark Edel ** ** This is free software; you can redistribute it and/or modify it under the ** terms of the GNU General Public License as published by the Free Software ** Foundation; either version 2 of the License, or (at your option) any later ** version. ** ** This software is distributed in the hope that it will be useful, but WITHOUT ** ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ** FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ** for more details. ** ** You should have received a copy of the GNU General Public License along with ** software; if not, write to the Free Software Foundation, Inc., 59 Temple ** Place, Suite 330, Boston, MA 02111-1307 USA ** ** Nirvana Text Editor ** June 15, 1995 ** ** Written by Mark Edel ** ********************************************************************************/#ifdef HAVE_CONFIG_H#include "../config.h"#endif#include "textBuf.h"#include "rangeset.h"#include <stdio.h>#include <stdlib.h>#include <string.h>#include <ctype.h>#include <Xm/Xm.h>#ifdef HAVE_DEBUG_H#include "../debug.h"#endif#define PREFERRED_GAP_SIZE 80 /* Initial size for the buffer gap (empty space in the buffer where text might be inserted if the user is typing sequential chars) */static void histogramCharacters(const char *string, int length, char hist[256], int init);static void subsChars(char *string, int length, char fromChar, char toChar);static char chooseNullSubsChar(char hist[256]);static int insert(textBuffer *buf, int pos, const char *text);static void delete(textBuffer *buf, int start, int end);static void deleteRect(textBuffer *buf, int start, int end, int rectStart, int rectEnd, int *replaceLen, int *endPos);static void insertCol(textBuffer *buf, int column, int startPos, const char *insText, int *nDeleted, int *nInserted, int *endPos);static void overlayRect(textBuffer *buf, int startPos, int rectStart, int rectEnd, const char *insText, int *nDeleted, int *nInserted, int *endPos);static void insertColInLine(const char *line, const char *insLine, int column, int insWidth, int tabDist, int useTabs, char nullSubsChar, char *outStr, int *outLen, int *endOffset);static void deleteRectFromLine(const char *line, int rectStart, int rectEnd, int tabDist, int useTabs, char nullSubsChar, char *outStr, int *outLen, int *endOffset);static void overlayRectInLine(const char *line, const char *insLine, int rectStart, int rectEnd, int tabDist, int useTabs, char nullSubsChar, char *outStr, int *outLen, int *endOffset);static void callPreDeleteCBs(textBuffer *buf, int pos, int nDeleted);static void callModifyCBs(textBuffer *buf, int pos, int nDeleted, int nInserted, int nRestyled, char *deletedText);static void redisplaySelection(textBuffer *buf, selection *oldSelection, selection *newSelection);static void moveGap(textBuffer *buf, int pos);static void reallocateBuf(textBuffer *buf, int newGapStart, int newGapLen);static void setSelection(selection *sel, int start, int end);static void setRectSelect(selection *sel, int start, int end, int rectStart, int rectEnd);static void updateSelections(textBuffer *buf, int pos, int nDeleted, int nInserted);static void updateSelection(selection *sel, int pos, int nDeleted, int nInserted);static int getSelectionPos(selection *sel, int *start, int *end, int *isRect, int *rectStart, int *rectEnd);static char *getSelectionText(textBuffer *buf, selection *sel);static void removeSelected(textBuffer *buf, selection *sel);static void replaceSelected(textBuffer *buf, selection *sel, const char *text);static void addPadding(char *string, int startIndent, int toIndent, int tabDist, int useTabs, char nullSubsChar, int *charsAdded);static int searchForward(textBuffer *buf, int startPos, char searchChar, int *foundPos);static int searchBackward(textBuffer *buf, int startPos, char searchChar, int *foundPos);static char *copyLine(const char *text, int *lineLen);static int countLines(const char *string);static int textWidth(const char *text, int tabDist, char nullSubsChar);static void findRectSelBoundariesForCopy(textBuffer *buf, int lineStartPos, int rectStart, int rectEnd, int *selStart, int *selEnd);static char *realignTabs(const char *text, int origIndent, int newIndent, int tabDist, int useTabs, char nullSubsChar, int *newLength);static char *expandTabs(const char *text, int startIndent, int tabDist, char nullSubsChar, int *newLen);static char *unexpandTabs(const char *text, int startIndent, int tabDist, char nullSubsChar, int *newLen);static int max(int i1, int i2);static int min(int i1, int i2);#ifdef __MVS__static const char *ControlCodeTable[64] = { "nul", "soh", "stx", "etx", "sel", "ht", "rnl", "del", "ge", "sps", "rpt", "vt", "ff", "cr", "so", "si", "dle", "dc1", "dc2", "dc3", "res", "nl", "bs", "poc", "can", "em", "ubs", "cu1", "ifs", "igs", "irs", "ius", "ds", "sos", "fs", "wus", "byp", "lf", "etb", "esc", "sa", "sfe", "sm", "csp", "mfa", "enq", "ack", "bel", "x30", "x31", "syn", "ir", "pp", "trn", "nbs", "eot", "sbs", "it", "rff", "cu3", "dc4", "nak", "x3e", "sub"};#elsestatic const char *ControlCodeTable[32] = { "nul", "soh", "stx", "etx", "eot", "enq", "ack", "bel", "bs", "ht", "nl", "vt", "np", "cr", "so", "si", "dle", "dc1", "dc2", "dc3", "dc4", "nak", "syn", "etb", "can", "em", "sub", "esc", "fs", "gs", "rs", "us"};#endif/*** Create an empty text buffer*/textBuffer *BufCreate(void){ textBuffer *buf = BufCreatePreallocated(0); return buf;}/*** Create an empty text buffer of a pre-determined size (use this to** avoid unnecessary re-allocation if you know exactly how much the buffer** will need to hold*/textBuffer *BufCreatePreallocated(int requestedSize){ textBuffer *buf; buf = (textBuffer *)XtMalloc(sizeof(textBuffer)); buf->length = 0; buf->buf = XtMalloc(requestedSize + PREFERRED_GAP_SIZE); buf->gapStart = 0; buf->gapEnd = PREFERRED_GAP_SIZE; buf->tabDist = 8; buf->useTabs = True; buf->primary.selected = False; buf->primary.zeroWidth = False; buf->primary.rectangular = False; buf->primary.start = buf->primary.end = 0; buf->secondary.selected = False; buf->secondary.zeroWidth = False; buf->secondary.start = buf->secondary.end = 0; buf->secondary.rectangular = False; buf->highlight.selected = False; buf->highlight.zeroWidth = False; buf->highlight.start = buf->highlight.end = 0; buf->highlight.rectangular = False; buf->modifyProcs = NULL; buf->cbArgs = NULL; buf->nModifyProcs = 0; buf->preDeleteProcs = NULL; buf->preDeleteCbArgs = NULL; buf->nPreDeleteProcs = 0; buf->nullSubsChar = '\0';#ifdef PURIFY {int i; for (i=buf->gapStart; i<buf->gapEnd; i++) buf->buf[i] = '.';}#endif buf->rangesetTable = NULL; return buf;}/*** Free a text buffer*/void BufFree(textBuffer *buf){ XtFree(buf->buf); if (buf->nModifyProcs != 0) { XtFree((char *)buf->modifyProcs); XtFree((char *)buf->cbArgs); } if (buf->rangesetTable) RangesetTableFree(buf->rangesetTable); if (buf->nPreDeleteProcs != 0) { XtFree((char *)buf->preDeleteProcs); XtFree((char *)buf->preDeleteCbArgs); } XtFree((char *)buf);}/*** Get the entire contents of a text buffer. Memory is allocated to contain** the returned string, which the caller must free.*/char *BufGetAll(textBuffer *buf){ char *text; text = XtMalloc(buf->length+1); memcpy(text, buf->buf, buf->gapStart); memcpy(&text[buf->gapStart], &buf->buf[buf->gapEnd], buf->length - buf->gapStart); text[buf->length] = '\0'; return text;}/*** Replace the entire contents of the text buffer*/void BufSetAll(textBuffer *buf, const char *text){ int length, deletedLength; char *deletedText; length = strlen(text); callPreDeleteCBs(buf, 0, buf->length); /* Save information for redisplay, and get rid of the old buffer */ deletedText = BufGetAll(buf); deletedLength = buf->length; XtFree(buf->buf); /* Start a new buffer with a gap of PREFERRED_GAP_SIZE in the center */ buf->buf = XtMalloc(length + PREFERRED_GAP_SIZE); buf->length = length; buf->gapStart = length/2; buf->gapEnd = buf->gapStart + PREFERRED_GAP_SIZE; memcpy(buf->buf, text, buf->gapStart); memcpy(&buf->buf[buf->gapEnd], &text[buf->gapStart], length-buf->gapStart);#ifdef PURIFY {int i; for (i=buf->gapStart; i<buf->gapEnd; i++) buf->buf[i] = '.';}#endif /* Zero all of the existing selections */ updateSelections(buf, 0, deletedLength, 0); /* Call the saved display routine(s) to update the screen */ callModifyCBs(buf, 0, deletedLength, length, 0, deletedText); XtFree(deletedText);}/*** Return a copy of the text between "start" and "end" character positions** from text buffer "buf". Positions start at 0, and the range does not** include the character pointed to by "end"*/char *BufGetRange(textBuffer *buf, int start, int end){ char *text; int length, part1Length; /* Make sure start and end are ok, and allocate memory for returned string. If start is bad, return "", if end is bad, adjust it. */ if (start < 0 || start > buf->length) { text = XtMalloc(1); text[0] = '\0'; return text; } if (end < start) { int temp = start; start = end; end = temp; } if (end > buf->length) end = buf->length; length = end - start; text = XtMalloc(length+1); /* Copy the text from the buffer to the returned string */ if (end <= buf->gapStart) { memcpy(text, &buf->buf[start], length); } else if (start >= buf->gapStart) { memcpy(text, &buf->buf[start+(buf->gapEnd-buf->gapStart)], length); } else { part1Length = buf->gapStart - start; memcpy(text, &buf->buf[start], part1Length); memcpy(&text[part1Length], &buf->buf[buf->gapEnd], length-part1Length); } text[length] = '\0'; return text;}/*** Return the character at buffer position "pos". Positions start at 0.*/char BufGetCharacter(textBuffer *buf, int pos){ if (pos < 0 || pos >= buf->length) return '\0'; if (pos < buf->gapStart) return buf->buf[pos]; else return buf->buf[pos + buf->gapEnd-buf->gapStart];}/*** Insert null-terminated string "text" at position "pos" in "buf"*/void BufInsert(textBuffer *buf, int pos, const char *text){ int nInserted; /* if pos is not contiguous to existing text, make it */ if (pos > buf->length) pos = buf->length; if (pos < 0 ) pos = 0; /* Even if nothing is deleted, we must call these callbacks */ callPreDeleteCBs(buf, pos, 0); /* insert and redisplay */ nInserted = insert(buf, pos, text); buf->cursorPosHint = pos + nInserted; callModifyCBs(buf, pos, 0, nInserted, 0, NULL);}/*** Delete the characters between "start" and "end", and insert the** null-terminated string "text" in their place in in "buf"*/void BufReplace(textBuffer *buf, int start, int end, const char *text){ char *deletedText; int nInserted = strlen(text); callPreDeleteCBs(buf, start, end-start); deletedText = BufGetRange(buf, start, end); delete(buf, start, end); insert(buf, start, text); buf->cursorPosHint = start + nInserted; callModifyCBs(buf, start, end-start, nInserted, 0, deletedText); XtFree(deletedText);}void BufRemove(textBuffer *buf, int start, int end){ char *deletedText; /* Make sure the arguments make sense */ if (start > end) { int temp = start; start = end; end = temp; } if (start > buf->length) start = buf->length; if (start < 0) start = 0; if (end > buf->length) end = buf->length; if (end < 0) end = 0; callPreDeleteCBs(buf, start, end-start); /* Remove and redisplay */ deletedText = BufGetRange(buf, start, end); delete(buf, start, end); buf->cursorPosHint = start; callModifyCBs(buf, start, end-start, 0, 0, deletedText); XtFree(deletedText);}void BufCopyFromBuf(textBuffer *fromBuf, textBuffer *toBuf, int fromStart, int fromEnd, int toPos){ int length = fromEnd - fromStart; int part1Length; /* Prepare the buffer to receive the new text. If the new text fits in the current buffer, just move the gap (if necessary) to where the text should be inserted. If the new text is too large, reallocate the buffer with a gap large enough to accomodate the new text and a gap of PREFERRED_GAP_SIZE */ if (length > toBuf->gapEnd - toBuf->gapStart) reallocateBuf(toBuf, toPos, length + PREFERRED_GAP_SIZE); else if (toPos != toBuf->gapStart) moveGap(toBuf, toPos); /* Insert the new text (toPos now corresponds to the start of the gap) */ if (fromEnd <= fromBuf->gapStart) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -