From accf34f276b200f87d30bc0800895420798ed2ff Mon Sep 17 00:00:00 2001 From: Matthias Melcher Date: Sun, 7 Nov 2010 20:13:50 +0000 Subject: Implemented search backwards for utf-8. Tested on MSWindows - OK. Tested on Linux (Ubuntu) - K. git-svn-id: file:///fltk/svn/fltk/branches/branch-1.3@7808 ea41ed52-d2ee-0310-a9c1-e6b18d33e121 --- FL/Fl_Text_Buffer.H | 59 +----------------------------------- src/Fl_Text_Buffer.cxx | 79 ++++++++++++++++++++++++++++++------------------- src/Fl_Text_Display.cxx | 15 ++++------ src/fl_utf8.cxx | 8 ++--- 4 files changed, 58 insertions(+), 103 deletions(-) diff --git a/FL/Fl_Text_Buffer.H b/FL/Fl_Text_Buffer.H index cc9e0be70..6a00f8a14 100644 --- a/FL/Fl_Text_Buffer.H +++ b/FL/Fl_Text_Buffer.H @@ -175,7 +175,6 @@ typedef void (*Fl_Text_Predelete_Cb)(int pos, int nDeleted, void* cbArg); The Fl_Text_Buffer class is used by the Fl_Text_Display and Fl_Text_Editor to manage complex text data and is based upon the excellent NEdit text editor engine - see http://www.nedit.org/. - \todo unicode check */ class FL_EXPORT Fl_Text_Buffer { public: @@ -212,7 +211,6 @@ public: /** Replaces the entire contents of the text buffer. \param text Text must be valid utf8. - \todo unicode check */ void text(const char* text); @@ -270,7 +268,6 @@ public: /** Appends the text string to the end of the buffer. \param t utf-8 encoded and nul terminated text - \todo unicode check */ void append(const char* t) { insert(length(), t); } @@ -295,14 +292,12 @@ public: \param fromStart byte offset into buffer \param fromEnd byte offset into buffer \param toPos destination byte offset into buffer - \todo unicode check */ void copy(Fl_Text_Buffer* fromBuf, int fromStart, int fromEnd, int toPos); /** Undo text modification according to the undo variables or insert text from the undo buffer - \todo unicode check */ int undo(int *cp=0); @@ -316,7 +311,6 @@ public: non-zero on error (strerror() contains reason). 1 indicates open for read failed (no data loaded). 2 indicates error occurred while reading data (data was partially loaded). - \todo unicode check */ int insertfile(const char *file, int pos, int buflen = 128*1024); @@ -325,14 +319,12 @@ public: success, non-zero on error (strerror() contains reason). 1 indicates open for read failed (no data loaded). 2 indicates error occurred while reading data (data was partially loaded). - \todo unicode check */ int appendfile(const char *file, int buflen = 128*1024) { return insertfile(file, length(), buflen); } /** Loads a text file into the buffer - \todo unicode check */ int loadfile(const char *file, int buflen = 128*1024) { select(0, length()); remove_selection(); return appendfile(file, buflen); } @@ -342,33 +334,28 @@ public: on error (strerror() contains reason). 1 indicates open for write failed (no data saved). 2 indicates error occurred while writing data (data was partially saved). - \todo unicode check */ int outputfile(const char *file, int start, int end, int buflen = 128*1024); /** Saves a text file from the current buffer - \todo unicode check */ int savefile(const char *file, int buflen = 128*1024) { return outputfile(file, 0, length(), buflen); } /** Gets the tab width. - \todo unicode check */ int tab_distance() const { return mTabDist; } /** Set the hardware tab distance (width) used by all displays for this buffer, and used in computing offsets for rectangular selection operations. - \todo unicode check */ void tab_distance(int tabDist); /** Selects a range of characters in the buffer. - \todo unicode check */ void select(int start, int end); @@ -379,38 +366,32 @@ public: /** Cancels any previous selection on the primary text selection object - \todo unicode check */ void unselect(); /** Gets the selection position - \todo unicode check */ int selection_position(int* start, int* end); /** Returns the currently selected text. When you are done with the text, free it using the free() function. - \todo unicode check */ char* selection_text(); /** Removes the text in the primary selection. - \todo unicode check */ void remove_selection(); /** Replaces the text in the primary selection. - \todo unicode check */ void replace_selection(const char* text); /** Selects a range of characters in the secondary selection. - \todo unicode check */ void secondary_select(int start, int end); @@ -422,39 +403,33 @@ public: /** Clears any selection in the secondary text selection object. - \todo unicode check */ void secondary_unselect(); /** Returns the current selection in the secondary text selection object. - \todo unicode check */ int secondary_selection_position(int* start, int* end); /** Returns the text in the secondary selection. When you are done with the text, free it using the free() function. - \todo unicode check */ char* secondary_selection_text(); /** Removes the text from the buffer corresponding to the secondary text selection object. - \todo unicode check */ void remove_secondary_selection(); /** Replaces the text from the buffer corresponding to the secondary text selection object with the new string \p text. - \todo unicode check */ void replace_secondary_selection(const char* text); /** Highlights the specified text within the buffer. - \todo unicode check */ void highlight(int start, int end); @@ -466,20 +441,17 @@ public: /** Unhighlights text in the buffer. - \todo unicode check */ void unhighlight(); /** Highlights the specified text between \p start and \p end within the buffer. - \todo unicode check */ int highlight_position(int* start, int* end); /** Returns the highlighted text. When you are done with the text, free it using the free() function. - \todo unicode check */ char* highlight_text(); @@ -492,13 +464,11 @@ public: int nRestyled, const char* deletedText, void* cbArg); \endcode - \todo unicode check */ void add_modify_callback(Fl_Text_Modify_Cb bufModifiedCB, void* cbArg); /** Removes a modify callback. - \todo unicode check */ void remove_modify_callback(Fl_Text_Modify_Cb bufModifiedCB, void* cbArg); @@ -506,27 +476,23 @@ public: Calls all modify callbacks that have been registered using the add_modify_callback() method. - \todo unicode check */ void call_modify_callbacks() { call_modify_callbacks(0, 0, 0, 0, 0); } /** Adds a callback routine to be called before text is deleted from the buffer. - \todo unicode check */ void add_predelete_callback(Fl_Text_Predelete_Cb bufPredelCB, void* cbArg); /** Removes a callback routine \p bufPreDeleteCB associated with argument \p cbArg to be called before text is deleted from the buffer. - \todo unicode check */ void remove_predelete_callback(Fl_Text_Predelete_Cb predelCB, void* cbArg); /** Calls the stored pre-delete callback procedure(s) for this buffer to update the changed area(s) on the screen and any other listeners. - \todo unicode check */ void call_predelete_callbacks() { call_predelete_callbacks(0, 0); } @@ -536,7 +502,6 @@ public: using the free() function. \param pos byte index into buffer \return copy of utf8 text, must be free'd - \todo unicode check */ char* line_text(int pos) const; @@ -544,7 +509,6 @@ public: Returns the position of the start of the line containing position \p pos. \param pos byte index into buffer \return byte offset to line start - \todo unicode check */ int line_start(int pos) const; @@ -554,7 +518,6 @@ public: or a pointer to one character beyond the end of the buffer) \param pos byte index into buffer \return byte offset to line end - \todo unicode check */ int line_end(int pos) const; @@ -562,7 +525,6 @@ public: Returns the position corresponding to the start of the word \param pos byte index into buffer \return byte offset to word start - \todo unicode check */ int word_start(int pos) const; @@ -570,7 +532,6 @@ public: Returns the position corresponding to the end of the word. \param pos byte index into buffer \return byte offset to word end - \todo unicode check */ int word_end(int pos) const; @@ -579,7 +540,6 @@ public: \p lineStartPos and \p targetPos. (displayed characters are the characters shown on the screen to represent characters in the buffer, where tabs and control characters are expanded) - \todo unicode check */ int count_displayed_characters(int lineStartPos, int targetPos) const; @@ -590,21 +550,18 @@ public: \param lineStartPos byte offset into buffer \param nChars number of bytes that are sent to the display \return byte offset in input after all output bytes are sent - \todo unicode check */ int skip_displayed_characters(int lineStartPos, int nChars); /** Counts the number of newlines between \p startPos and \p endPos in buffer. The character at position \p endPos is not counted. - \todo unicode check */ int count_lines(int startPos, int endPos) const; /** Finds the first character of the line \p nLines forward from \p startPos in the buffer and returns its position - \todo unicode check */ int skip_lines(int startPos, int nLines); @@ -612,7 +569,6 @@ public: Finds and returns the position of the first character of the line \p nLines backwards from \p startPos (not counting the character pointed to by \p startpos if that is a newline) in the buffer. \p nLines == 0 means find the beginning of the line - \todo unicode check */ int rewind_lines(int startPos, int nLines); @@ -628,7 +584,6 @@ public: \param searchChar UCS-4 character that we want to find \param foundPos byte offset where the character was found \return 1 if found, 0 if not - \todo unicode check */ int findchar_forward(int startPos, unsigned searchChar, int* foundPos) const; @@ -643,7 +598,6 @@ public: \param searchChar UCS-4 character that we want to find \param foundPos byte offset where the character was found \return 1 if found, 0 if not - \todo unicode check */ int findchar_backward(int startPos, unsigned searchChar, int* foundPos) const; @@ -656,7 +610,6 @@ public: \param foundPos byte offset where the string was found \param matchCase if set, match character case \return 1 if found, 0 if not - \todo unicode check */ int search_forward(int startPos, const char* searchString, int* foundPos, int matchCase = 0) const; @@ -670,7 +623,6 @@ public: \param foundPos byte offset where the string was found \param matchCase if set, match character case \return 1 if found, 0 if not - \todo unicode check */ int search_backward(int startPos, const char* searchString, int* foundPos, int matchCase = 0) const; @@ -733,7 +685,6 @@ protected: /** Calls the stored modify callback procedure(s) for this buffer to update the changed area(s) on the screen and any other listeners. - \todo unicode check */ void call_modify_callbacks(int pos, int nDeleted, int nInserted, int nRestyled, const char* deletedText) const; @@ -741,7 +692,6 @@ protected: /** Calls the stored pre-delete callback procedure(s) for this buffer to update the changed area(s) on the screen and any other listeners. - \todo unicode check */ void call_predelete_callbacks(int pos, int nDeleted) const; @@ -752,7 +702,6 @@ protected: on to call redisplay). \p pos must be contiguous with the existing text in the buffer (i.e. not past the end). \return the number of bytes inserted - \todo unicode check */ int insert_(int pos, const char* text); @@ -760,27 +709,24 @@ protected: Internal (non-redisplaying) version of BufRemove. Removes the contents of the buffer between start and end (and moves the gap to the site of the delete). - \todo unicode check */ void remove_(int start, int end); /** Calls the stored redisplay procedure(s) for this buffer to update the screen for a change in a selection. - \todo unicode check */ void redisplay_selection(Fl_Text_Selection* oldSelection, Fl_Text_Selection* newSelection) const; /** - \todo unicode check + Move the gap to start at a new position. */ void move_gap(int pos); /** Reallocates the text storage in the buffer to have a gap starting at \p newGapStart and a gap size of \p newGapLen, preserving the buffer's current contents. - \todo unicode check */ void reallocate_with_gap(int newGapStart, int newGapLen); @@ -788,19 +734,16 @@ protected: /** Removes the text from the buffer corresponding to \p sel. - \todo unicode check */ void remove_selection_(Fl_Text_Selection* sel); /** Replaces the \p text in selection \p sel. - \todo unicode check */ void replace_selection_(Fl_Text_Selection* sel, const char* text); /** Updates all of the selections in the buffer for changes in the buffer's text - \todo unicode check */ void update_selections(int pos, int nDeleted, int nInserted); diff --git a/src/Fl_Text_Buffer.cxx b/src/Fl_Text_Buffer.cxx index 531ec5029..52666333e 100644 --- a/src/Fl_Text_Buffer.cxx +++ b/src/Fl_Text_Buffer.cxx @@ -856,13 +856,11 @@ int Fl_Text_Buffer::word_end(int pos) const { /* - Matt: I am not sure why we need this function. Does it still make sense in - the world of proportional characters? + Count the number of characters between two positions. */ int Fl_Text_Buffer::count_displayed_characters(int lineStartPos, int targetPos) const { - // FIXME: this is misleading and may be used to count bytes instead of characters! IS_UTF8_ALIGNED(address(lineStartPos)) IS_UTF8_ALIGNED(address(targetPos)) @@ -878,16 +876,13 @@ int Fl_Text_Buffer::count_displayed_characters(int lineStartPos, /* - Matt: I am not sure why we need this function. Does it still make sense in - the world of proportional characters? + Skip ahead a number of characters from a given index. + This function breaks early if it encounters a newline character. */ -// All values are number of bytes. -// - unicode ok? int Fl_Text_Buffer::skip_displayed_characters(int lineStartPos, int nChars) { - // FIXME: this is misleading and may be used to count bytes instead of characters! IS_UTF8_ALIGNED(address(lineStartPos)) - // FIXME: is this function still needed? + int pos = lineStartPos; for (int charCount = 0; charCount < nChars && pos < mLength; charCount++) { @@ -1060,37 +1055,60 @@ int Fl_Text_Buffer::search_forward(int startPos, const char *searchString, return 0; } - -/* - Find a matching string in the buffer. - NOT TESTED FOR UNICODE. - */ int Fl_Text_Buffer::search_backward(int startPos, const char *searchString, - int *foundPos, int matchCase) const { - // FIXME: Unicode? + int *foundPos, int matchCase) const +{ + IS_UTF8_ALIGNED(address(startPos)) + IS_UTF8_ALIGNED(searchString) + if (!searchString) return 0; int bp; const char *sp; - while (startPos > 0) - { - bp = startPos - 1; - sp = searchString + strlen(searchString) - 1; - do { - if (sp < searchString) { - *foundPos = bp + 1; - return 1; + if (matchCase) { + while (startPos >= 0) { + bp = startPos; + sp = searchString; + for (;;) { + char c = *sp; + // we reached the end of the "needle", so we found the string! + if (!c) { + *foundPos = startPos; + return 1; + } + int l = fl_utf8len(c); + if (memcmp(sp, address(bp), l)) + break; + sp += l; bp += l; } - // FIXME: character is ucs-4 - } while ((matchCase ? char_at(bp--) == (unsigned int)*sp-- : - toupper(char_at(bp--)) == toupper(*sp--)) - && bp >= 0); - startPos--; - } + startPos = prev_char(startPos); + } + } else { + while (startPos >= 0) { + bp = startPos; + sp = searchString; + for (;;) { + // we reached the end of the "needle", so we found the string! + if (!*sp) { + *foundPos = startPos; + return 1; + } + int l; + unsigned int b = char_at(bp); + unsigned int s = fl_utf8decode(sp, 0, &l); + if (fl_tolower(b)!=fl_tolower(s)) + break; + sp += l; + bp = next_char(bp); + } + startPos = prev_char(startPos); + } + } return 0; } + /* Insert a string into the buffer. Pos must be at a character boundary. Text must be a correct utf8 string. @@ -1422,7 +1440,6 @@ void Fl_Text_Buffer::update_selections(int pos, int nDeleted, // unicode safe, assuming the arguments are on character boundaries void Fl_Text_Selection::update(int pos, int nDeleted, int nInserted) { - // FIXME: check if this is safe when seletion crosses selction boundaries if (!mSelected || pos > mEnd) return; if (pos + nDeleted <= mStart) { diff --git a/src/Fl_Text_Display.cxx b/src/Fl_Text_Display.cxx index a9e7c8b6b..48f726f69 100644 --- a/src/Fl_Text_Display.cxx +++ b/src/Fl_Text_Display.cxx @@ -33,6 +33,7 @@ // TODO: verify all "byte counts" vs. "character counts" // TODO: rendering of the Tab character // TODO: rendering of the "optional hyphen" +// TODO: make line numbering work again #include #include @@ -948,8 +949,6 @@ void Fl_Text_Display::display_insert() { hOffset = mHorizOffset; topLine = mTopLineNum; - // FIXME: I don't understand this well enough to know if it is correct - // it is different than nedit 5.3 if (insert_position() < mFirstChar) { topLine -= count_lines(insert_position(), mFirstChar, false); } else if (mLineStarts[mNVisibleLines-2] != -1) { @@ -1296,8 +1295,8 @@ int Fl_Text_Display::rewind_lines(int startPos, int nLines) { -// FIXME: this does not take UCS-4 encoding into account static inline int fl_isseparator(unsigned int c) { + // FIXME: this does not take UCS-4 encoding into account return c != '$' && c != '_' && (isspace(c) || ispunct(c)); } @@ -1333,7 +1332,7 @@ void Fl_Text_Display::previous_word() { while (pos && fl_isseparator(buffer()->char_at(pos))) { pos = buffer()->prev_char(pos); } - // FIXME: character is ucs-4 + while (pos && !fl_isseparator(buffer()->char_at(pos))) { pos = buffer()->prev_char(pos); } @@ -1663,7 +1662,7 @@ int Fl_Text_Display::position_to_line( int pos, int *lineNum ) const { \retval FIND_INDEX x pixel position inside given block \todo we need to handle hidden hyphens and tabs here! \todo we handle all styles and selections - \todo we must provide code to get pixle positions of the middle of a character as well + \todo we must provide code to get pixel positions of the middle of a character as well */ int Fl_Text_Display::handle_vline( int mode, @@ -2572,8 +2571,6 @@ void Fl_Text_Display::h_scrollbar_cb(Fl_Scrollbar* b, Fl_Text_Display* textD) { */ void Fl_Text_Display::draw_line_numbers(bool /*clearAll*/) { #if 0 - // FIXME: don't want this yet, so will leave for another time - int y, line, visLine, nCols, lineStart; char lineNumString[12]; int lineHeight = mMaxsize ? mMaxsize : textsize_; @@ -2940,9 +2937,7 @@ void Fl_Text_Display::measure_deleted_lines(int pos, int nDeleted) { } else lineStart = retPos; nLines++; - if (lineStart > pos + nDeleted && - // FIXME: character is ucs-4 - buf->char_at(lineStart-1) == '\n') { + if (lineStart > pos + nDeleted && buf->char_at(lineStart-1) == '\n') { break; } diff --git a/src/fl_utf8.cxx b/src/fl_utf8.cxx index 1cd809eed..6d69a588e 100644 --- a/src/fl_utf8.cxx +++ b/src/fl_utf8.cxx @@ -378,11 +378,11 @@ int fl_latin12utf(const unsigned char *str, int len, char *buf) */ unsigned int fl_nonspacing(unsigned int ucs) { -#ifdef __APPLE__ - return (ucs==0x20); // FIXME: what does this really do? -#else +//#ifdef __APPLE__ +// return (ucs==0x20); // FIXME: what does this really do? +//#else return (unsigned int) XUtf8IsNonSpacing(ucs); -#endif +//#endif } #if defined(WIN32) && !defined(__CYGWIN__) -- cgit v1.2.3