fl_text_buffer.cxx
来自「SRI international 发布的OAA框架软件」· CXX 代码 · 共 1,884 行 · 第 1/5 页
CXX
1,884 行
//
// "$Id: Fl_Text_Buffer.cxx,v 1.1.1.1 2003/06/03 22:25:43 agno Exp $"
//
// Copyright 2001-2003 by Bill Spitzak and others.
// Original code Copyright Mark Edel. Permission to distribute under
// the LGPL for the FLTK library granted by Mark Edel.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library 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
// Library General Public License for more details.
//
// You should have received a copy of the GNU Library General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
// USA.
//
// Please report all bugs and problems to "fltk-bugs@fltk.org".
//
#include <stdio.h>
#include <stdlib.h>
#include "flstring.h"
#include <ctype.h>
#include <FL/Fl.H>
#include <FL/Fl_Text_Buffer.H>
#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 void insertColInLine( const char *line, 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, char *insLine, int rectStart,
int rectEnd, int tabDist, int useTabs, char nullSubsChar, char *outStr,
int *outLen, int *endOffset );
static void addPadding( char *string, int startIndent, int toIndent,
int tabDist, int useTabs, char nullSubsChar, int *charsAdded );
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 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( char *text, int startIndent, int tabDist,
char nullSubsChar, int *newLen );
static int max( int i1, int i2 );
static int min( int i1, int i2 );
static 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"};
static char* undobuffer;
static int undobufferlength;
static Fl_Text_Buffer* undowidget;
static int undoat; // points after insertion
static int undocut; // number of characters deleted there
static int undoinsert; // number of characters inserted
static int undoyankcut; // length of valid contents of buffer, even if undocut=0
static void undobuffersize(int n) {
if (n > undobufferlength) {
if (undobuffer) {
do {undobufferlength *= 2;} while (undobufferlength < n);
undobuffer = (char*)realloc(undobuffer, undobufferlength);
} else {
undobufferlength = n+9;
undobuffer = (char*)malloc(undobufferlength);
}
}
}
/*
** 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
*/
Fl_Text_Buffer::Fl_Text_Buffer( int requestedSize ) {
mLength = 0;
mBuf = (char *)malloc( requestedSize + PREFERRED_GAP_SIZE );
mGapStart = 0;
mGapEnd = PREFERRED_GAP_SIZE;
mTabDist = 8;
mUseTabs = 1;
mPrimary.mSelected = 0;
mPrimary.mRectangular = 0;
mPrimary.mStart = mPrimary.mEnd = 0;
mSecondary.mSelected = 0;
mSecondary.mStart = mSecondary.mEnd = 0;
mSecondary.mRectangular = 0;
mHighlight.mSelected = 0;
mHighlight.mStart = mHighlight.mEnd = 0;
mHighlight.mRectangular = 0;
mNodifyProcs = NULL;
mCbArgs = NULL;
mNModifyProcs = 0;
mNPredeleteProcs = 0;
mPredeleteProcs = NULL;
mPredeleteCbArgs = NULL;
mCursorPosHint = 0;
mNullSubsChar = '\0';
mCanUndo = 1;
#ifdef PURIFY
{ int i; for (i = mGapStart; i < mGapEnd; i++) mBuf[ i ] = '.'; }
#endif
}
/*
** Free a text buffer
*/
Fl_Text_Buffer::~Fl_Text_Buffer() {
free( mBuf );
if ( mNModifyProcs != 0 ) {
delete[] mNodifyProcs;
delete[] mCbArgs;
}
if ( mNPredeleteProcs != 0 ) {
delete[] mPredeleteProcs;
delete[] mPredeleteCbArgs;
}
}
/*
** Get the entire contents of a text buffer. Memory is allocated to contain
** the returned string, which the caller must free.
*/
char * Fl_Text_Buffer::text() {
char *t;
t = (char *)malloc( mLength + 1 );
memcpy( t, mBuf, mGapStart );
memcpy( &t[ mGapStart ], &mBuf[ mGapEnd ],
mLength - mGapStart );
t[ mLength ] = '\0';
return t;
}
/*
** Replace the entire contents of the text buffer
*/
void Fl_Text_Buffer::text( const char *t ) {
int insertedLength, deletedLength;
const char *deletedText;
call_predelete_callbacks(0, length());
/* Save information for redisplay, and get rid of the old buffer */
deletedText = text();
deletedLength = mLength;
free( (void *)mBuf );
/* Start a new buffer with a gap of PREFERRED_GAP_SIZE in the center */
insertedLength = strlen( t );
mBuf = (char *)malloc( insertedLength + PREFERRED_GAP_SIZE );
mLength = insertedLength;
mGapStart = insertedLength / 2;
mGapEnd = mGapStart + PREFERRED_GAP_SIZE;
memcpy( mBuf, t, mGapStart );
memcpy( &mBuf[ mGapEnd ], &t[ mGapStart ], insertedLength - mGapStart );
#ifdef PURIFY
{ int i; for ( i = mGapStart; i < mGapEnd; i++ ) mBuf[ i ] = '.'; }
#endif
/* Zero all of the existing selections */
update_selections( 0, deletedLength, 0 );
/* Call the saved display routine(s) to update the screen */
call_modify_callbacks( 0, deletedLength, insertedLength, 0, deletedText );
free( (void *)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 * Fl_Text_Buffer::text_range( int start, int end ) {
char * s;
int copiedLength, 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 > mLength ) {
s = (char *)malloc( 1 );
s[ 0 ] = '\0';
return s;
}
if ( end < start ) {
int temp = start;
start = end;
end = temp;
}
if ( end > mLength )
end = mLength;
copiedLength = end - start;
s = (char *)malloc( copiedLength + 1 );
/* Copy the text from the buffer to the returned string */
if ( end <= mGapStart ) {
memcpy( s, &mBuf[ start ], copiedLength );
} else if ( start >= mGapStart ) {
memcpy( s, &mBuf[ start + ( mGapEnd - mGapStart ) ], copiedLength );
} else {
part1Length = mGapStart - start;
memcpy( s, &mBuf[ start ], part1Length );
memcpy( &s[ part1Length ], &mBuf[ mGapEnd ], copiedLength - part1Length );
}
s[ copiedLength ] = '\0';
return s;
}
/*
** Return the character at buffer position "pos". Positions start at 0.
*/
char Fl_Text_Buffer::character( int pos ) {
if ( pos < 0 || pos >= mLength )
return '\0';
if ( pos < mGapStart )
return mBuf[ pos ];
else
return mBuf[ pos + mGapEnd - mGapStart ];
}
/*
** Insert null-terminated string "text" at position "pos" in "buf"
*/
void Fl_Text_Buffer::insert( int pos, const char *s ) {
int nInserted;
/* if pos is not contiguous to existing text, make it */
if ( pos > mLength ) pos = mLength;
if ( pos < 0 ) pos = 0;
/* Even if nothing is deleted, we must call these callbacks */
call_predelete_callbacks( pos, 0 );
/* insert and redisplay */
nInserted = insert_( pos, s );
mCursorPosHint = pos + nInserted;
call_modify_callbacks( 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 Fl_Text_Buffer::replace( int start, int end, const char *s ) {
const char * deletedText;
int nInserted;
call_predelete_callbacks( start, end-start );
deletedText = text_range( start, end );
remove_( start, end );
//undoyankcut = undocut;
nInserted = insert_( start, s );
mCursorPosHint = start + nInserted;
call_modify_callbacks( start, end - start, nInserted, 0, deletedText );
free( (void *)deletedText );
}
void Fl_Text_Buffer::remove( int start, int end ) {
const char * deletedText;
/* Make sure the arguments make sense */
if ( start > end ) {
int temp = start;
start = end;
end = temp;
}
if ( start > mLength ) start = mLength;
if ( start < 0 ) start = 0;
if ( end > mLength ) end = mLength;
if ( end < 0 ) end = 0;
call_predelete_callbacks( start, end-start );
/* Remove and redisplay */
deletedText = text_range( start, end );
remove_( start, end );
mCursorPosHint = start;
call_modify_callbacks( start, end - start, 0, 0, deletedText );
free( (void *)deletedText );
}
void Fl_Text_Buffer::copy( Fl_Text_Buffer *fromBuf, int fromStart,
int fromEnd, int toPos ) {
int copiedLength = 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 ( copiedLength > mGapEnd - mGapStart )
reallocate_with_gap( toPos, copiedLength + PREFERRED_GAP_SIZE );
else if ( toPos != mGapStart )
move_gap( toPos );
/* Insert the new text (toPos now corresponds to the start of the gap) */
if ( fromEnd <= fromBuf->mGapStart ) {
memcpy( &mBuf[ toPos ], &fromBuf->mBuf[ fromStart ], copiedLength );
} else if ( fromStart >= fromBuf->mGapStart ) {
memcpy( &mBuf[ toPos ],
&fromBuf->mBuf[ fromStart + ( fromBuf->mGapEnd - fromBuf->mGapStart ) ],
copiedLength );
} else {
part1Length = fromBuf->mGapStart - fromStart;
memcpy( &mBuf[ toPos ], &fromBuf->mBuf[ fromStart ], part1Length );
memcpy( &mBuf[ toPos + part1Length ], &fromBuf->mBuf[ fromBuf->mGapEnd ],
copiedLength - part1Length );
}
mGapStart += copiedLength;
mLength += copiedLength;
update_selections( toPos, 0, copiedLength );
}
/*
** remove text according to the undo variables or insert text
** from the undo buffer
*/
int Fl_Text_Buffer::undo(int *cursorPos) {
if (undowidget != this || !undocut && !undoinsert &&!mCanUndo) return 0;
int ilen = undocut;
int xlen = undoinsert;
int b = undoat-xlen;
if (xlen && undoyankcut && !ilen) {
ilen = undoyankcut;
}
if (xlen && ilen) {
undobuffersize(ilen+1);
undobuffer[ilen] = 0;
char *tmp = strdup(undobuffer);
replace(b, undoat, tmp);
if (cursorPos) *cursorPos = mCursorPosHint;
free(tmp);
}
else if (xlen) {
remove(b, undoat);
if (cursorPos) *cursorPos = mCursorPosHint;
}
else if (ilen) {
undobuffersize(ilen+1);
undobuffer[ilen] = 0;
insert(undoat, undobuffer);
if (cursorPos) *cursorPos = mCursorPosHint;
undoyankcut = 0;
}
return 1;
}
/*
** let the undo system know if we can undo changes
*/
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?