2 // "$Id: Fl_Text_Buffer.H 8148 2010-12-31 22:38:03Z matt $"
4 // Header file for Fl_Text_Buffer class.
6 // Copyright 2001-2010 by Bill Spitzak and others.
7 // Original code Copyright Mark Edel. Permission to distribute under
8 // the LGPL for the FLTK library granted by Mark Edel.
10 // This library is free software; you can redistribute it and/or
11 // modify it under the terms of the GNU Library General Public
12 // License as published by the Free Software Foundation; either
13 // version 2 of the License, or (at your option) any later version.
15 // This library is distributed in the hope that it will be useful,
16 // but WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 // Library General Public License for more details.
20 // You should have received a copy of the GNU Library General Public
21 // License along with this library; if not, write to the Free Software
22 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
25 // Please report all bugs and problems on the following page:
27 // http://www.fltk.org/str.php
31 Fl_Text_Buffer, Fl_Text_Selection widget . */
33 #ifndef FL_TEXT_BUFFER_H
34 #define FL_TEXT_BUFFER_H
41 # define IS_UTF8_ALIGNED(a) if (a && *a) assert(fl_utf8len(*(a))>0);
42 # define IS_UTF8_ALIGNED2(a, b) if (b>=0 && b<a->length()) assert(fl_utf8len(a->byte_at(b))>0);
44 # define IS_UTF8_ALIGNED(a)
45 # define IS_UTF8_ALIGNED2(a, b)
50 "character size" is the size of a UTF-8 character in bytes
51 "character width" is the width of a Unicode character in pixels
52 "column" was orginally defined as a character offset from the left margin.
53 It was identical to the byte offset. In UTF-8, we have neither a byte offset
54 nor truly fixed width fonts (*). Column could be a pixel value multiplied with
55 an average character width (which is a bearable approximation).
57 * in Unicode, there are no fixed width fonts! Even if the ASCII characters may
58 happen to be all the same width in pixels, chinese charcaters surely are not.
59 There are plenty of exceptions, like ligatures, that make special handling of
60 "fixed" character widths a nightmare. I decided to remove all references to
61 fixed fonts and see "columns" as a multiple of the average width of a
62 character in the main font.
67 /* Maximum length in characters of a tab or control character expansion
68 of a single buffer character */
69 #define FL_TEXT_MAX_EXP_CHAR_LEN 20
71 #include "Fl_Export.H"
75 \class Fl_Text_Selection
76 \brief This is an internal class for Fl_Text_Buffer to manage text selections.
77 This class works correctly with utf-8 strings assuming that the parameters
78 for all calls are on character boundaries.
80 class FL_EXPORT Fl_Text_Selection {
81 friend class Fl_Text_Buffer;
86 \brief Set the selection range.
87 \param start byte offset to first selected character
88 \param end byte offset pointing after last selected character
90 void set(int start, int end);
93 \brief Updates a selection afer text was modified.
94 Updates an individual selection for changes in the corresponding text
95 \param pos byte offset into text buffer at which the change occured
96 \param nDeleted number of bytes deleted from the buffer
97 \param nInserted number of bytes inserted into the buffer
99 void update(int pos, int nDeleted, int nInserted);
102 \brief Return the byte offset to the first selected character.
105 int start() const { return mStart; }
108 \brief Return the byte ofsset to the character after the last selected character.
111 int end() const { return mEnd; }
114 \brief Returns true if any text is selected.
115 \return a non-zero number if any text has been selected, or 0
116 if no text is selected.
118 bool selected() const { return mSelected; }
121 \brief Modify the 'selected' flag.
124 void selected(bool b) { mSelected = b; }
127 Return true if position \p pos with indentation \p dispIndex is in
128 the Fl_Text_Selection.
130 int includes(int pos) const;
133 \brief Return the positions of this selection.
134 \param start retrun byte offset to first selected character
135 \param end retrun byte offset pointing after last selected character
136 \return true if selected
138 int position(int* start, int* end) const;
142 int mStart; ///< byte offset to the first selected character
143 int mEnd; ///< byte offset to the character after the last selected character
144 bool mSelected; ///< this flag is set if any text is selected
148 typedef void (*Fl_Text_Modify_Cb)(int pos, int nInserted, int nDeleted,
149 int nRestyled, const char* deletedText,
153 typedef void (*Fl_Text_Predelete_Cb)(int pos, int nDeleted, void* cbArg);
157 \brief This class manages unicode displayed in one or more Fl_Text_Display widgets.
159 All text in Fl_Text_Buffermust be encoded in UTF-8. All indices used in the
160 function calls must be aligned to the start of a UTF-8 sequence. All indices
161 and pointers returned will be aligned. All functions that return a single
162 character will return that in an unsiged int in UCS-4 encoding.
164 The Fl_Text_Buffer class is used by the Fl_Text_Display
165 and Fl_Text_Editor to manage complex text data and is based upon the
166 excellent NEdit text editor engine - see http://www.nedit.org/.
168 class FL_EXPORT Fl_Text_Buffer {
172 Create an empty text buffer of a pre-determined size.
173 \param requestedSize use this to avoid unnecessary re-allocation
174 if you know exactly how much the buffer will need to hold
175 \param preferredGapSize Initial size for the buffer gap (empty space
176 in the buffer where text might be inserted
177 if the user is typing sequential chars)
179 Fl_Text_Buffer(int requestedSize = 0, int preferredGapSize = 1024);
187 \brief Returns the number of bytes in the buffer.
188 \return size of text in bytes
190 int length() const { return mLength; }
193 \brief Get a copy of the entire contents of the text buffer.
194 Memory is allocated to contain the returned string, which the caller
196 \return newly allocated text buffer - must be free'd, text is utf8
201 Replaces the entire contents of the text buffer.
202 \param text Text must be valid utf8.
204 void text(const char* text);
207 \brief Get a copy of a part of the text buffer.
208 Return a copy of the text between \p start and \p end character positions
209 from text buffer \p buf. Positions start at 0, and the range does not
210 include the character pointed to by \p end.
211 When you are done with the text, free it using the free() function.
212 \param start byte offset to first character
213 \param end byte offset after last character in range
214 \return newly allocated text buffer - must be free'd, text is utf8
216 char* text_range(int start, int end) const;
219 Returns the character at the specified position pos in the buffer.
221 \param pos byte offset into buffer, pos must be at acharacter boundary
222 \return Unicode UCS-4 encoded character
224 unsigned int char_at(int pos) const;
227 Returns the raw byte at the specified position pos in the buffer.
229 \param pos byte offset into buffer
230 \return unencoded raw byte
232 char byte_at(int pos) const;
235 Convert a byte offset in buffer into a memory address.
236 \param pos byte offset into buffer
237 \return byte offset converted to a memory address
239 const char *address(int pos) const
240 { return (pos < mGapStart) ? mBuf+pos : mBuf+pos+mGapEnd-mGapStart; }
243 Convert a byte offset in buffer into a memory address.
244 \param pos byte offset into buffer
245 \return byte offset converted to a memory address
247 char *address(int pos)
248 { return (pos < mGapStart) ? mBuf+pos : mBuf+pos+mGapEnd-mGapStart; }
251 Inserts null-terminated string \p text at position \p pos.
252 \param pos insertion position as byte offset (must be utf-8 character aligned)
253 \param text utf-8 encoded and nul terminated text
255 void insert(int pos, const char* text);
258 Appends the text string to the end of the buffer.
259 \param t utf-8 encoded and nul terminated text
261 void append(const char* t) { insert(length(), t); }
264 Deletes a range of characters in the buffer.
265 \param start byte offset to first character to be removed
266 \param end byte offset to charcatre after last character to be removed
268 void remove(int start, int end);
271 Deletes the characters between \p start and \p end, and inserts the null-terminated string \p text in their place in the buffer.
272 \param start byte offset to first character to be removed and new insert position
273 \param end byte offset to charcatre after last character to be removed
274 \param text utf-8 encoded and nul terminated text
276 void replace(int start, int end, const char *text);
279 Copies text from one buffer to this one.
280 \param fromBuf source text buffer may be the same as this
281 \param fromStart byte offset into buffer
282 \param fromEnd byte offset into buffer
283 \param toPos destination byte offset into buffer
285 void copy(Fl_Text_Buffer* fromBuf, int fromStart, int fromEnd, int toPos);
288 Undo text modification according to the undo variables or insert text
294 Lets the undo system know if we can undo changes
296 void canUndo(char flag=1);
299 Inserts a file at the specified position. Returns 0 on success,
300 non-zero on error (strerror() contains reason). 1 indicates open
301 for read failed (no data loaded). 2 indicates error occurred
302 while reading data (data was partially loaded).
303 File can be UTF-8 or CP1252-encoded.
304 If the input file is not UTF-8-encoded, the Fl_Text_Buffer widget will contain
305 UTF-8-transcoded data. By default, the message Fl_Text_Buffer::file_encoding_warning_message
306 will warn the user about this.
307 \see input_file_was_transcoded and transcoding_warning_action.
309 int insertfile(const char *file, int pos, int buflen = 128*1024);
312 Appends the named file to the end of the buffer. See also insertfile().
314 int appendfile(const char *file, int buflen = 128*1024)
315 { return insertfile(file, length(), buflen); }
318 Loads a text file into the buffer. See also insertfile().
320 int loadfile(const char *file, int buflen = 128*1024)
321 { select(0, length()); remove_selection(); return appendfile(file, buflen); }
324 Writes the specified portions of the file to a file. Returns 0 on success, non-zero
325 on error (strerror() contains reason). 1 indicates open for write failed
326 (no data saved). 2 indicates error occurred while writing data
327 (data was partially saved).
329 int outputfile(const char *file, int start, int end, int buflen = 128*1024);
332 Saves a text file from the current buffer
334 int savefile(const char *file, int buflen = 128*1024)
335 { return outputfile(file, 0, length(), buflen); }
340 int tab_distance() const { return mTabDist; }
343 Set the hardware tab distance (width) used by all displays for this buffer,
344 and used in computing offsets for rectangular selection operations.
346 void tab_distance(int tabDist);
349 Selects a range of characters in the buffer.
351 void select(int start, int end);
354 Returns a non 0 value if text has been selected, 0 otherwise
356 int selected() const { return mPrimary.selected(); }
359 Cancels any previous selection on the primary text selection object
364 Gets the selection position
366 int selection_position(int* start, int* end);
369 Returns the currently selected text. When you are done with
370 the text, free it using the free() function.
372 char* selection_text();
375 Removes the text in the primary selection.
377 void remove_selection();
380 Replaces the text in the primary selection.
382 void replace_selection(const char* text);
385 Selects a range of characters in the secondary selection.
387 void secondary_select(int start, int end);
390 Returns a non 0 value if text has been selected in the secondary
391 text selection, 0 otherwise
393 int secondary_selected() { return mSecondary.selected(); }
396 Clears any selection in the secondary text selection object.
398 void secondary_unselect();
401 Returns the current selection in the secondary text selection object.
403 int secondary_selection_position(int* start, int* end);
406 Returns the text in the secondary selection. When you are
407 done with the text, free it using the free() function.
409 char* secondary_selection_text();
412 Removes the text from the buffer corresponding to the secondary text selection object.
414 void remove_secondary_selection();
417 Replaces the text from the buffer corresponding to the secondary
418 text selection object with the new string \p text.
420 void replace_secondary_selection(const char* text);
423 Highlights the specified text within the buffer.
425 void highlight(int start, int end);
428 Returns the highlighted text. When you are done with the
429 text, free it using the free() function.
431 int highlight() { return mHighlight.selected(); }
434 Unhighlights text in the buffer.
439 Highlights the specified text between \p start and \p end within the buffer.
441 int highlight_position(int* start, int* end);
444 Returns the highlighted text. When you are done with the
445 text, free it using the free() function.
447 char* highlight_text();
450 Adds a callback function that is called whenever the text buffer is
451 modified. The callback function is declared as follows:
454 typedef void (*Fl_Text_Modify_Cb)(int pos, int nInserted, int nDeleted,
455 int nRestyled, const char* deletedText,
459 void add_modify_callback(Fl_Text_Modify_Cb bufModifiedCB, void* cbArg);
462 Removes a modify callback.
464 void remove_modify_callback(Fl_Text_Modify_Cb bufModifiedCB, void* cbArg);
467 Calls all modify callbacks that have been registered using
468 the add_modify_callback()
471 void call_modify_callbacks() { call_modify_callbacks(0, 0, 0, 0, 0); }
474 Adds a callback routine to be called before text is deleted from the buffer.
476 void add_predelete_callback(Fl_Text_Predelete_Cb bufPredelCB, void* cbArg);
479 Removes a callback routine \p bufPreDeleteCB associated with argument \p cbArg
480 to be called before text is deleted from the buffer.
482 void remove_predelete_callback(Fl_Text_Predelete_Cb predelCB, void* cbArg);
485 Calls the stored pre-delete callback procedure(s) for this buffer to update
486 the changed area(s) on the screen and any other listeners.
488 void call_predelete_callbacks() { call_predelete_callbacks(0, 0); }
491 Returns the text from the entire line containing the specified
492 character position. When you are done with the text, free it
493 using the free() function.
494 \param pos byte index into buffer
495 \return copy of utf8 text, must be free'd
497 char* line_text(int pos) const;
500 Returns the position of the start of the line containing position \p pos.
501 \param pos byte index into buffer
502 \return byte offset to line start
504 int line_start(int pos) const;
507 Finds and returns the position of the end of the line containing position \p pos
508 (which is either a pointer to the newline character ending the line,
509 or a pointer to one character beyond the end of the buffer)
510 \param pos byte index into buffer
511 \return byte offset to line end
513 int line_end(int pos) const;
516 Returns the position corresponding to the start of the word
517 \param pos byte index into buffer
518 \return byte offset to word start
520 int word_start(int pos) const;
523 Returns the position corresponding to the end of the word.
524 \param pos byte index into buffer
525 \return byte offset to word end
527 int word_end(int pos) const;
530 Count the number of displayed characters between buffer position
531 \p lineStartPos and \p targetPos. (displayed characters are the characters
532 shown on the screen to represent characters in the buffer, where tabs and
533 control characters are expanded)
535 int count_displayed_characters(int lineStartPos, int targetPos) const;
538 Count forward from buffer position \p startPos in displayed characters
539 (displayed characters are the characters shown on the screen to represent
540 characters in the buffer, where tabs and control characters are expanded)
541 \param lineStartPos byte offset into buffer
542 \param nChars number of bytes that are sent to the display
543 \return byte offset in input after all output bytes are sent
545 int skip_displayed_characters(int lineStartPos, int nChars);
548 Counts the number of newlines between \p startPos and \p endPos in buffer.
549 The character at position \p endPos is not counted.
551 int count_lines(int startPos, int endPos) const;
554 Finds the first character of the line \p nLines forward from \p startPos
555 in the buffer and returns its position
557 int skip_lines(int startPos, int nLines);
560 Finds and returns the position of the first character of the line \p nLines backwards
561 from \p startPos (not counting the character pointed to by \p startpos if
562 that is a newline) in the buffer. \p nLines == 0 means find the beginning of the line
564 int rewind_lines(int startPos, int nLines);
567 Finds the next occurrence of the specified character.
568 Search forwards in buffer for character \p searchChar, starting
569 with the character \p startPos, and returning the result in \p foundPos
570 returns 1 if found, 0 if not. (The difference between this and
571 BufSearchForward is that it's optimized for single characters. The
572 overall performance of the text widget is dependent on its ability to
573 count lines quickly, hence searching for a single character: newline)
574 \param startPos byte offset to start position
575 \param searchChar UCS-4 character that we want to find
576 \param foundPos byte offset where the character was found
577 \return 1 if found, 0 if not
579 int findchar_forward(int startPos, unsigned searchChar, int* foundPos) const;
582 Search backwards in buffer \p buf for character \p searchChar, starting
583 with the character BEFORE \p startPos, returning the result in \p foundPos
584 returns 1 if found, 0 if not. (The difference between this and
585 BufSearchBackward is that it's optimized for single characters. The
586 overall performance of the text widget is dependent on its ability to
587 count lines quickly, hence searching for a single character: newline)
588 \param startPos byte offset to start position
589 \param searchChar UCS-4 character that we want to find
590 \param foundPos byte offset where the character was found
591 \return 1 if found, 0 if not
593 int findchar_backward(int startPos, unsigned int searchChar, int* foundPos) const;
596 Search forwards in buffer for string \p searchString, starting with the
597 character \p startPos, and returning the result in \p foundPos
598 returns 1 if found, 0 if not.
599 \param startPos byte offset to start position
600 \param searchString utf8 string that we want to find
601 \param foundPos byte offset where the string was found
602 \param matchCase if set, match character case
603 \return 1 if found, 0 if not
605 int search_forward(int startPos, const char* searchString, int* foundPos,
606 int matchCase = 0) const;
609 Search backwards in buffer for string <i>searchCharssearchString</i>, starting with the
610 character BEFORE \p startPos, returning the result in \p foundPos
611 returns 1 if found, 0 if not.
612 \param startPos byte offset to start position
613 \param searchString utf8 string that we want to find
614 \param foundPos byte offset where the string was found
615 \param matchCase if set, match character case
616 \return 1 if found, 0 if not
618 int search_backward(int startPos, const char* searchString, int* foundPos,
619 int matchCase = 0) const;
622 Returns the primary selection.
624 const Fl_Text_Selection* primary_selection() const { return &mPrimary; }
627 Returns the primary selection.
629 Fl_Text_Selection* primary_selection() { return &mPrimary; }
632 Returns the secondary selection.
634 const Fl_Text_Selection* secondary_selection() const { return &mSecondary; }
637 Returns the current highlight selection.
639 const Fl_Text_Selection* highlight_selection() const { return &mHighlight; }
642 Returns the index of the previous character.
643 \param ix index to the current char
645 int prev_char(int ix) const;
646 int prev_char_clipped(int ix) const;
649 Returns the index of the next character.
650 \param ix index to the current char
652 int next_char(int ix) const;
653 int next_char_clipped(int ix) const;
656 Align an index into the buffer to the current or previous utf8 boundary.
658 int utf8_align(int) const;
661 \brief true iff the loaded file has been transcoded to UTF-8
663 int input_file_was_transcoded;
665 /** This message may be displayed using the fl_alert() function when a file
666 which was not UTF-8 encoded is input.
668 static const char* file_encoding_warning_message;
671 \brief Pointer to a function called after reading a non UTF-8 encoded file.
673 This function is called after reading a file if the file content
674 was transcoded to UTF-8. Its default implementation calls fl_alert()
675 with the text of \ref file_encoding_warning_message. No warning message is
676 displayed if this pointer is set to NULL. Use \ref input_file_was_transcoded
677 to be informed if file input required transcoding to UTF-8.
679 void (*transcoding_warning_action)(Fl_Text_Buffer*);
684 Calls the stored modify callback procedure(s) for this buffer to update the
685 changed area(s) on the screen and any other listeners.
687 void call_modify_callbacks(int pos, int nDeleted, int nInserted,
688 int nRestyled, const char* deletedText) const;
691 Calls the stored pre-delete callback procedure(s) for this buffer to update
692 the changed area(s) on the screen and any other listeners.
694 void call_predelete_callbacks(int pos, int nDeleted) const;
697 Internal (non-redisplaying) version of BufInsert. Returns the length of
698 text inserted (this is just strlen(\p text), however this calculation can be
699 expensive and the length will be required by any caller who will continue
700 on to call redisplay). \p pos must be contiguous with the existing text in
701 the buffer (i.e. not past the end).
702 \return the number of bytes inserted
704 int insert_(int pos, const char* text);
707 Internal (non-redisplaying) version of BufRemove. Removes the contents
708 of the buffer between start and end (and moves the gap to the site of
711 void remove_(int start, int end);
714 Calls the stored redisplay procedure(s) for this buffer to update the
715 screen for a change in a selection.
717 void redisplay_selection(Fl_Text_Selection* oldSelection,
718 Fl_Text_Selection* newSelection) const;
721 Move the gap to start at a new position.
723 void move_gap(int pos);
726 Reallocates the text storage in the buffer to have a gap starting at \p newGapStart
727 and a gap size of \p newGapLen, preserving the buffer's current contents.
729 void reallocate_with_gap(int newGapStart, int newGapLen);
731 char* selection_text_(Fl_Text_Selection* sel) const;
734 Removes the text from the buffer corresponding to \p sel.
736 void remove_selection_(Fl_Text_Selection* sel);
739 Replaces the \p text in selection \p sel.
741 void replace_selection_(Fl_Text_Selection* sel, const char* text);
744 Updates all of the selections in the buffer for changes in the buffer's text
746 void update_selections(int pos, int nDeleted, int nInserted);
748 Fl_Text_Selection mPrimary; /**< highlighted areas */
749 Fl_Text_Selection mSecondary; /**< highlighted areas */
750 Fl_Text_Selection mHighlight; /**< highlighted areas */
751 int mLength; /**< length of the text in the buffer (the length
752 of the buffer itself must be calculated:
753 gapEnd - gapStart + length) */
754 char* mBuf; /**< allocated memory where the text is stored */
755 int mGapStart; /**< points to the first character of the gap */
756 int mGapEnd; /**< points to the first char after the gap */
757 // The hardware tab distance used by all displays for this buffer,
758 // and used in computing offsets for rectangular selection operations.
759 int mTabDist; /**< equiv. number of characters in a tab */
760 int mNModifyProcs; /**< number of modify-redisplay procs attached */
761 Fl_Text_Modify_Cb *mModifyProcs;/**< procedures to call when buffer is
762 modified to redisplay contents */
763 void** mCbArgs; /**< caller arguments for modifyProcs above */
764 int mNPredeleteProcs; /**< number of pre-delete procs attached */
765 Fl_Text_Predelete_Cb *mPredeleteProcs; /**< procedure to call before text is deleted
766 from the buffer; at most one is supported. */
767 void **mPredeleteCbArgs; /**< caller argument for pre-delete proc above */
768 int mCursorPosHint; /**< hint for reasonable cursor position after
769 a buffer modification operation */
770 char mCanUndo; /**< if this buffer is used for attributes, it must
771 not do any undo calls */
772 int mPreferredGapSize; /**< the default allocation for the text gap is 1024
773 bytes and should only be increased if frequent
774 and large changes in buffer size are expected */
780 // End of "$Id: Fl_Text_Buffer.H 8148 2010-12-31 22:38:03Z matt $".