1 /* Bluefish HTML Editor 2 * bftextview2.h 3 * 4 * Copyright (C) 2008,2009,2010,2011,2012,2013,2014 Olivier Sessink 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 3 of the License, or 9 * (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program. If not, see <http://www.gnu.org/licenses/>. 18 */ 19 20 /* 21 BFTEXTVIEW2 DESIGN DOCS 22 23 requirements: a textwidget with 24 - syntax highlighting 25 - block folding 26 - context-sensitive autocompletion 27 - for various languages 28 - fast (doesn't lock the GUI when syntaxt-scanning very large files) 29 30 ============= The widget code ============= 31 - to avoid locking the GUI, it should be able to scan in multiple runs 32 - it should be able to mark a region as 'needs scanning' 33 - it should be able to resume scanning on any point marked as 'needs scanning' 34 35 the widget code, including signal handlers and idle handlers are in bftextview2.c 36 37 ============== Syntax scanning ============= 38 - scanning is done with patterns that scan within a context 39 - for e.g. php we start with an html context that scans for html tags and it scans 40 for the php-open tag <?php 41 - within a html tag we scan the html-attribute context and we scan for the end-of-tag '>' 42 - withing <?php we scan for functions/variables and for end-of-php '?>' 43 - autocompletion is also done based on the context. so for autocompletion we look-up 44 the context, and based on the context we know the possibilities 45 - for e.g. scanning within the '<img' html tag context we know that 'src' is one of 46 the valid attributes 47 - the context is kept on a stack. once the end-of-context pattern is found (a pattern that has 48 nextcontext -1), we revert to the previous context 49 50 - changed areas are marked with a GtkTextTag called 'needscanning'. 51 - a idle function is started (if not running) to do the actual scanning 52 - the scanner keeps a timer and stops scanning once a certain time has passed 53 - if the scanning is finished the idle function stops 54 55 56 ============ The scanned syntax cache ============ 57 - to find where to resume scanning it simply searches for the first position 58 that is marked with the needscanning tag 59 - to know which patterns to use we have to know in which context we are. we therefore keep 60 a cache of the (context)stack. on each position where the contextstack changes, we make a copy 61 of the current state and store it in a sorted balanced tree (a GSequence), sorted by the 62 character offset in the text. We store a Tfound structure. A member of the Tfound structure 63 is a pointer to the Tfoundcontext stucture which describes the current context. 64 - the positions change when text is inserted or deleted, but never their order. a GSequence 65 allows us to update the offsets for the stacks without re-sorting the entire tree 66 - same holds for the blocks. we keep a blockstack, and we keep a cache of the blockstack in the 67 same foundcache as where we keep the contextstack. The member of the Tfound structure that 68 describes the state for blocks is the Tfoundblock structure. 69 70 - when a new block is found, a Tfound structure has a member fblock of type Tfoundblock 71 that points to the new block, and member numblockchange is 1. That Tfoundblock has a 72 pointer to it's parent block. 73 - when an end-of-block is found, the Tfound structure has again a member fblock that 74 points to the popped block, and numblockchange is -1. So to get the active block *after* 75 a popped block, you have to look at the parent of the fblock member!!!! 76 - the Tfound member charoffset_o has the character offset of the end-of-the-end-of-context-match 77 (Tfoundcontext->end_o) or the end-of-the-end-of-block-match (Tfoundblock->end2_o). 78 79 The next ascii art shows how blocks are stored in the scancache. This is a special situation 80 in which a second block starts but does not have an end, so both blocks are popped at 'f'. A 81 Tfound structure is saved at offset B, D and F. 82 83 --------------------Block-1-with-valid-end-------------------- 84 | | | | 85 | | ------Block-without-end-------|--| 86 | | | | | | 87 -----a--B------------------------c---D-------------------------e--F--------- 88 | | | | | | 89 | |Tfound numblockchange=1 | |Tfound numblockchange=1 | |Tfound nublockchange=-2 90 | |end1_o == charoffset_o | |end1_o == charoffset_o | | end2_o == charoffset_o for the block1 91 | | | 92 |start1_o |start1_o |start2_o for block1 93 94 95 - to paint the margin and detect if we can expand/collapse blocks, we can use this same 96 scancache. Along with walking the lines to draw the line numbers we walk the GSequence 97 and see in the Tfound structures if there are new blocks that can be folded. 98 99 100 =========== Scanning with a DFA engine ============== 101 - the current scanning is based on Deterministic Finite Automata (DFA) just like the 1.1.6 102 unstable engine (see wikipedia for more info). The 1.1.6 engine alloc's each state in a 103 separate memory block. This new engine alloc's a large array for all states at once, so you can 104 simply move trough the array instead of following pointers. 105 The array is the array 'table' in structure Tcontext. So each context has it's own 106 DFA table. Following the DFA is then as simple as state = table[state][character]; 107 where state is just an integer position in the array, and character is the current character 108 you're scanning. The array will help to speed up the scanner. I used guint16 because I 109 suspect that we never hit the 65500 states for a single context (largest patterns set right 110 now is php, 4500 functions use 32000 states). 111 When a state has a positive result (it matches something) it has an index number to 112 an array 'matches' in structure Tscantable which is an array of type Tpattern structure 113 that has the information for the matched pattern. 114 115 - each context has it's own DFA table. The startcontext for each context is always 116 position 0 and the identstate is always position 1 in that array 117 118 - Compared to the engine in the 1.0 series the main advantage is that we do only a single scanning 119 run for all patterns in a given context. The 1.0 scanner does multiple scanning runs for <\?php 120 and for <[a-z]+>. The new engine scans (<\?php|<[a-z]+>) but knows that both sub-patterns lead 121 to different results (different color, different context). 122 123 ========== language parsing from the XML file ========== 124 - the languages are defined in an XML file. On startup, only the header of that file is parsed, 125 into a Tbflang struct, which defines the language and the mime types. Only when scanning for 126 one of these mime-types is requested the rest of the file is parsed (in a separate thread!!!) 127 and the DFA for this language is created. This saves memory and startup time for languages 128 that are not used in a certain session. 129 130 For parsing we use the libxml2 textreader interface 131 http://xmlsoft.org/xmlreader.html 132 It does not need to load the full XML file into memory, it 133 is a parser that moves through the file while parsing. This 134 makes it an excellent choice to quickly parse large language 135 files in order to build the DFA table. 136 137 A tag, keyword or patterns may have a class="foo" attribute. This pattern is only 138 added to the DFA when option "foo" is enabled. This way we can have gtk functions 139 in the C patterns for those of us that do GTK programming in Bluefish. All 140 others will have a much smaller DFA table for the C language. 141 142 Language file loading is done in bftextview2_langmgr.c, the found patterns are added 143 to the Tscantable structure and it's members (and compiled into a DFA table) 144 in bftextview2_patcompile.c. 145 146 ========== Symbols and identifiers in the DFA table ========== 147 Each context has symbols. Symbols are characters that may start or end a pattern. 148 Try to highlight for example: 149 char *rc_char(char*chara); 150 ^^^^ ^^^^ 151 Only two of the four 'char' need to be highlighted. How does the scanner know which 152 one to highlight? In the above example there are several symbols such as whitespace 153 , brackets and operators: 154 char *rc_char(char*chara); 155 ^ ^^ ^ ^ ^^ 156 see that the occurences of 'char' that should be highlighted are all in between symbols?! 157 158 The Tcontext structure has a startstate for each context and an identifier-state (identstate). 159 In the next example state 0 is the startstate and state 1 the identstate: 160 ----------------------------------------------------------------------- 161 |state|| space| a | c | h | r | * | ( | ) | _ | have match ? | 162 ----------------------------------------------------------------------- 163 | 0 || 0 | 1 | 2 | 1 | 1 | 0 | 0 | 0 | 1 | no | 164 | 1 || 0 | 1 | 1 | 1 | 1 | 0 | 0 | 0 | 1 | no | 165 | 2 || 0 | 1 | 1 | 3 | 1 | 0 | 0 | 0 | 1 | no | 166 | 3 || 0 | 4 | 1 | 1 | 1 | 0 | 0 | 0 | 1 | no | 167 | 4 || 0 | 1 | 1 | 1 | 5 | 0 | 0 | 0 | 1 | no | 168 | 5 || 0 | 1 | 1 | 1 | 1 | 0 | 0 | 0 | 1 | yes! we have: char | 169 ----------------------------------------------------------------------- 170 now try to parse the bit '(char*' starting at state 0 (the startstate) 171 ( -> state 0 if we find state 0 we check if there is a match.. no 172 c -> state 2 173 h -> state 3 174 a -> state 4 175 r -> state 5 176 * -> state 0 if we find state 0 we check if there is a match.. YES! 177 178 now try to scan the bit '*rc_char(' 179 * -> state 0 if we find state 0 we check if there is a match.. no 180 r -> state 1 181 c -> state 1 182 _ -> state 1 183 c -> state 1 184 h -> state 1 185 a -> state 1 186 r -> state 1 187 ( -> state 0 if we find state 0 we check if there is a match.. no 188 189 now try to scan the bit ' chara)': 190 -> state 0 if we find state 0 we check if there is a match.. no 191 c -> state 2 192 h -> state 3 193 a -> state 4 194 r -> state 5 195 a -> state 1 196 ) -> state 0 if we find state 0 we check if there is a match.. no 197 198 as you see, the scanner is stuck in state 1 (the identstate) if 199 either on the start or on the end there is no symbol. 200 201 ======== Autocompleting patterns ============= 202 for autocompletion we keep a GCompletion in each context (member 'ac' of structure Tcontext). 203 This is filled with all the patterns during XML load. 204 205 we use a similar scanning engine as above that can tell us where the string that 206 the user is typing started, and in which context the curor position is. Once 207 we know the context we know which GCompletion structure to use, so we can get 208 a list of possible completion strings. 209 210 The scanning for the context is done in bftextview2_scanner.c, the rest of the autocompletion 211 code is in bftextview2_autocomp.c 212 213 ======== Reference information ========== 214 reference information can be shown in a tooltip above the text and in a side window 215 during autocompletion. The reference information is stored in a member of the Tpattern 216 structure. Each Tcontext structure has a member patternhash that is a hashtable with the 217 match as key and the index to the pattern in array Tscantable->matches as value. 218 219 For the tooltip we do a short scanning run to find the context and which pattern is 220 actually under the cursor and we do a hash table lookup to find the corresponding 221 reference information. 222 223 ========= Spell checker =========== 224 the spell checker is in bftextview2_spell.c 225 226 after the syntax scanning is finished the spell checker is started. Similar to the syntax 227 scanner it runs in short timeslices such that it won't block the GUI. It scans only in 228 certain GtkTextTag's (for example in the GtktextTag for comments and for strings). 229 230 ======= Storing found function names and such for jump and autocompletion ====== 231 232 identifiers, such as function names or variable names can be stored for jump and for 233 autocompletion. Code is in bftextview2_identifier.c 234 235 for jump: found functions names are stored in a hashtable 236 bfwin->identifier_jump as 237 key Tbflang-context-name -> value Tdocument-linenumber 238 239 for autocompletion they are added to a GCompletion 240 the GCompletion can be found in hashtable 241 bfwin->identifier_ac with 242 key Tbflang-context -> value GCompletion 243 244 identifier_mode="1" means that the following the *following* identifier is to be stored. For example in 245 php 'function', and in python 'def' and 'class' (implemented in bluefish 2.0.3). 246 identifier_mode="2" means that the match itself is to be stored as an identifier, for example in php 247 the variable '$[a-zA-Z_][a-zA-Z0-9_]*' (implemented in 2.0.4) 248 249 ======= Split view / slave widget ======= 250 251 a slave widget is a widget that does not do scanning itself, it doesn't 252 have a scanning table, it doesn't have any settings. It relies for all 253 of these things on the master widget. On a master widget btv->master will 254 point to itself, on a slave widget btv->master will point to the master. 255 256 The slave widget should always be destroyed before the master. 257 */ 258 259 #ifndef _BFTEXTVIEW2_H_ 260 #define _BFTEXTVIEW2_H_ 261 262 #include <gtk/gtk.h> 263 #include "config.h" 264 265 #define IDENTSTORING 266 #define UPDATE_OFFSET_DELAYED 267 268 /* MARKREGION: the new code the store the text locations where scanning or spellcheck is required */ 269 #define MARKREGION 270 /* NEEDSCANNING: the old code the store the text locations where scanning or spellcheck is required. 271 if both old and new are defined, their results will be compared */ 272 /*#define NEEDSCANNING*/ 273 #ifndef NEEDSCANNING 274 #define MARKREGION 275 #endif 276 277 #ifdef MARKREGION 278 typedef struct { 279 gpointer head; 280 gpointer tail; 281 gpointer last; 282 } Tregions; 283 #endif 284 285 typedef enum { 286 comment_type_block, 287 comment_type_line 288 } Tcomment_type; 289 290 typedef struct { 291 gchar *so; 292 gchar *eo; 293 Tcomment_type type; 294 } Tcomment; 295 296 typedef struct { 297 guint8 allsymbols[128]; /* this lookup table holds all symbols for all contexts, and is used to trigger scanning if reduced_scan_triggers is enabled */ 298 GArray *contexts; /* dynamic sized array of Tcontext that translates a context number into a rownumber in the DFA table */ 299 GArray *matches; /* dynamic sized array of Tpattern */ 300 GArray *comments; /* array of Tcomment, has max. 256 entries, we use a guint8 as index */ 301 GArray *blocks; /* array of Tpattern_block with a guint16 as index */ 302 GArray *conditions; /* array of Tpattern_condition with a guint16 as index */ 303 } Tscantable; 304 305 typedef struct { 306 GSequence *foundcaches; /* a sorted structure of Tfound for 307 each position where the stack changes so we can restart scanning 308 on any location */ 309 #ifdef UPDATE_OFFSET_DELAYED 310 gpointer offsetupdates; /* points to the last Toffsetupdate in the list (has an embedded list) */ 311 #endif 312 } Tscancache; 313 /********************************/ 314 /* language manager */ 315 /********************************/ 316 typedef struct { 317 gchar *name; 318 GList *mimetypes; 319 GList *tags; /* all tags used for highlighting in this language. we use this list when 320 we want to remove all tags and want to re-highlight */ 321 gchar *filename; /* the .bflang2 file */ 322 Tscantable *st; /* NULL or complete */ 323 gchar *smartindentchars; 324 gchar *smartoutdentchars; 325 gchar *smartselectionchars; 326 #ifdef HAVE_LIBENCHANT 327 gboolean default_spellcheck; 328 gboolean spell_decode_entities; 329 #endif 330 gboolean no_st; /* no scantable, for Text, don't try to load the scantable if st=NULL */ 331 gboolean parsing; /* set to TRUE when a thread is parsing the scantable already */ 332 gboolean in_menu; /* set to TRUE to show this language in the menu */ 333 gint size_table; 334 gint size_contexts; 335 gint size_matches; 336 } Tbflang; 337 338 #define BFLANG(var) ((Tbflang *)var) 339 340 /* Color Configuation data */ 341 typedef enum { 342 BTV_COLOR_ED_BG, 343 BTV_COLOR_ED_FG, 344 BTV_COLOR_WHITESPACE, 345 BTV_COLOR_CURRENT_LINE, 346 BTV_COLOR_RIGHT_MARGIN, 347 BTV_COLOR_CURSOR, 348 BTV_COLOR_SELECTION, 349 BTV_COLOR_CURSOR_HIGHLIGHT, 350 BTV_COLOR_MARGIN_FG, 351 BTV_COLOR_MARGIN_BG, 352 /* BTV_COLOR_SEARCH_BG, 353 BTV_COLOR_SEARCH_FG,*/ 354 BTV_COLOR_COUNT 355 } Tbtv_colors; 356 357 358 /*****************************************************************/ 359 /* stuff for the widget */ 360 /*****************************************************************/ 361 362 #define BLUEFISH_TYPE_TEXT_VIEW (bluefish_text_view_get_type ()) 363 #define BLUEFISH_TEXT_VIEW(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), BLUEFISH_TYPE_TEXT_VIEW, BluefishTextView)) 364 #define BLUEFISH_TEXT_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), BLUEFISH_TYPE_TEXT_VIEW, BluefishTextViewClass)) 365 #define BLUEFISH_IS_TEXT_VIEW(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), BLUEFISH_TYPE_TEXT_VIEW)) 366 #define BLUEFISH_IS_TEXT_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), BLUEFISH_TYPE_TEXT_VIEW)) 367 #define BLUEFISH_TEXT_VIEW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), BLUEFISH_TYPE_TEXT_VIEW, BluefishTextViewClass)) 368 369 typedef struct _BluefishTextView BluefishTextView; 370 typedef struct _BluefishTextViewClass BluefishTextViewClass; 371 372 struct _BluefishTextView { 373 GtkTextView parent; 374 gpointer master; /* points usually to self, but in the case of a slave widget 375 (two widgets showing the same buffer it will point to the master widget) */ 376 gpointer slave; /* usually NULL, but might point to a slave widget */ 377 Tbflang *bflang; /* Tbflang */ 378 gpointer doc; /* Tdocument */ 379 GtkTextBuffer *buffer; 380 #ifdef NEEDSCANNING 381 GtkTextTag *needscanning; 382 #ifdef HAVE_LIBENCHANT 383 GtkTextTag *needspellcheck; 384 #endif /*HAVE_LIBENCHANT */ 385 #endif 386 #ifdef MARKREGION 387 Tregions scanning; 388 #ifdef HAVE_LIBENCHANT 389 Tregions spellcheck; 390 #endif /*HAVE_LIBENCHANT*/ 391 #endif /*MARKREGION*/ 392 GtkTextTag *blockmatch; 393 GtkTextTag *cursortag; 394 Tscancache scancache; 395 guint scanner_immediate; /* event ID for the high priority scanning run */ 396 guint scanner_idle; /* event ID for the idle function that handles the scanning. 0 if no idle function is running */ 397 guint scanner_delayed; /* event ID for the timeout function that handles the delayed scanning. 0 if no timeout function is running */ 398 GTimer *user_idle_timer; 399 guint user_idle; /* event ID for the timed function that handles user idle events such as autocompletion popups */ 400 guint mark_set_idle; /* event ID for the mark_set idle function that avoids showing matching block bounds while 401 you hold the arrow key to scroll quickly */ 402 gulong insert_text_id; 403 gulong insert_text_after_id; 404 gulong mark_set_id; 405 gulong delete_range_id; 406 gulong delete_range_after_id; 407 408 gpointer autocomp; /* a Tacwin* with the current autocompletion window */ 409 gboolean needs_autocomp; /* a state of the widget, autocomplete is needed on user keyboard actions */ 410 gboolean needs_blockmatch; /* a state of the widget, if the cursor position was changed */ 411 gboolean key_press_inserted_char; /* FALSE if the key press was used by autocomplete popup, or simply not in our widget */ 412 gdouble button_press_line; /* line location of the button press, used in the release */ 413 /*gboolean key_press_was_autocomplete; a state of the widget, if the last keypress was handled by the autocomplete popup window */ 414 gboolean showing_blockmatch; /* a state of the widget if we are currently showing a blockmatch */ 415 gboolean insert_was_auto_indent; /* a state of the widget if the last keypress (enter) caused 416 autoindent (so we should unindent on a closing bracket */ 417 guint needremovetags; /* after we have removed all old highlighting, we set this to G_MAXUINT32, or to the 418 offset up to the point where we removed the old highlighting. but after a change that 419 needs highlighting we set this to the offset of the change. */ 420 gint spacingtoclickstart; 421 gint spacingtoclickend; 422 423 /* next three are used for margin painting */ 424 gint margin_pixels_per_char; 425 gint margin_pixels_chars; 426 gint margin_pixels_block; 427 gint margin_pixels_symbol; 428 429 /* following options are simple true/false settings */ 430 gboolean enable_scanner; /* only run scanner when TRUE, this is FALSE if the document is in the background for example */ 431 gboolean auto_indent; 432 gboolean auto_complete; 433 gboolean show_line_numbers; 434 gboolean show_blocks; 435 gboolean showsymbols; 436 gboolean visible_spacing; 437 gboolean show_right_margin; 438 gboolean show_mbhl; /* show matching block highlighting */ 439 #ifdef HAVE_LIBENCHANT 440 gboolean spell_check; 441 #endif 442 }; 443 444 struct _BluefishTextViewClass { 445 GtkTextViewClass parent_class; 446 }; 447 448 GType bluefish_text_view_get_type(void); 449 const gchar *bluefish_text_view_get_lang_name(BluefishTextView *btv); 450 gboolean bluefish_text_view_get_active_block_boundaries(BluefishTextView *btv, guint location, gboolean innerblock, GtkTextIter *so, GtkTextIter *eo); 451 gboolean bluefish_text_view_get_active_identifier(BluefishTextView *btv, GtkTextIter *currentlocation, GtkTextIter *so, GtkTextIter *eo); 452 gpointer bftextview2_get_block_at_boundary_location(BluefishTextView *btv, guint offset, GtkTextIter *it1, GtkTextIter *it2, GtkTextIter *it3, GtkTextIter *it4); 453 gboolean bluefish_text_view_get_auto_complete(BluefishTextView * btv); 454 void bluefish_text_view_set_auto_complete(BluefishTextView * btv, gboolean enable); 455 gboolean bluefish_text_view_get_auto_indent(BluefishTextView * btv); 456 void bluefish_text_view_set_auto_indent(BluefishTextView * btv, gboolean enable); 457 void bftextview2_init_globals(void); 458 void bluefish_text_view_set_colors(BluefishTextView * btv, gchar * const *colors); 459 void bluefish_text_view_select_language(BluefishTextView * btv, const gchar * mime, const gchar * filename); 460 gboolean bluefish_text_view_get_show_blocks(BluefishTextView * btv); 461 void bluefish_text_view_set_show_blocks(BluefishTextView * btv, gboolean show); 462 void bluefish_text_view_set_show_symbols_redraw(BluefishTextView * btv, gboolean show); 463 gboolean bluefish_text_view_get_show_line_numbers(BluefishTextView * btv); 464 void bluefish_text_view_set_show_line_numbers(BluefishTextView * btv, gboolean show); 465 gboolean bluefish_text_view_get_show_visible_spacing(BluefishTextView * btv); 466 void bluefish_text_view_set_show_visible_spacing(BluefishTextView * btv, gboolean show); 467 gboolean bluefish_text_view_get_show_right_margin(BluefishTextView * btv); 468 void bluefish_text_view_set_show_right_margin(BluefishTextView * btv, gboolean show); 469 void bluefish_text_view_set_font(BluefishTextView *btv, PangoFontDescription *font_desc); 470 gboolean bluefish_text_view_get_show_mbhl(BluefishTextView * btv); 471 void bluefish_text_view_set_show_mbhl(BluefishTextView * btv, gboolean show); 472 #ifdef HAVE_LIBENCHANT 473 void bluefish_text_view_set_spell_check(BluefishTextView * btv, gboolean spell_check); 474 #endif 475 /* this functions is used in the widget in _autocomp.c */ 476 gchar *get_line_indenting(GtkTextBuffer * buffer, GtkTextIter * iter, gboolean prevline); 477 void bluefish_text_view_scan_cleanup(BluefishTextView * btv); 478 void bluefish_text_view_rescan(BluefishTextView * btv); 479 void bftextview2_schedule_scanning(BluefishTextView * btv); 480 gboolean bluefish_text_view_in_comment(BluefishTextView * btv, GtkTextIter * its, GtkTextIter * ite); 481 Tcomment *bluefish_text_view_get_comment(BluefishTextView * btv, GtkTextIter * it, 482 Tcomment_type preferred_type); 483 gboolean last_undo_is_spacingtoclick(BluefishTextView * btv); 484 void bluefish_text_view_remove_spacingtoclick(BluefishTextView * btv); 485 486 void bluefish_text_view_multiset(BluefishTextView * btv, gpointer doc, gint view_line_numbers, 487 gint view_blocks, gint autoindent, gint autocomplete, gint show_mbhl, gint enable_scanner); 488 489 GtkWidget *bftextview2_new(void); 490 GtkWidget *bftextview2_new_with_buffer(GtkTextBuffer * buffer); 491 GtkWidget *bftextview2_new_slave(BluefishTextView * master); 492 493 #endif 494