Blender V2.61 - r43446
|
00001 /* 00002 * ***** BEGIN GPL LICENSE BLOCK ***** 00003 * 00004 * This program is free software; you can redistribute it and/or 00005 * modify it under the terms of the GNU General Public License 00006 * as published by the Free Software Foundation; either version 2 00007 * of the License, or (at your option) any later version. 00008 * 00009 * This program is distributed in the hope that it will be useful, 00010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 * GNU General Public License for more details. 00013 * 00014 * You should have received a copy of the GNU General Public License 00015 * along with this program; if not, write to the Free Software Foundation, 00016 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00017 * 00018 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. 00019 * All rights reserved. 00020 * 00021 * The Original Code is: all of this file. 00022 * 00023 * Contributor(s): none yet. 00024 * 00025 * ***** END GPL LICENSE BLOCK ***** 00026 */ 00027 00033 #include <string.h> /* strstr */ 00034 #include <sys/types.h> 00035 #include <sys/stat.h> 00036 #include <wchar.h> 00037 #include <wctype.h> 00038 00039 #include "MEM_guardedalloc.h" 00040 00041 #include "BLI_blenlib.h" 00042 #include "BLI_utildefines.h" 00043 00044 #include "DNA_constraint_types.h" 00045 #include "DNA_controller_types.h" 00046 #include "DNA_scene_types.h" 00047 #include "DNA_screen_types.h" 00048 #include "DNA_space_types.h" 00049 #include "DNA_text_types.h" 00050 #include "DNA_userdef_types.h" 00051 #include "DNA_object_types.h" 00052 00053 #include "BKE_depsgraph.h" 00054 #include "BKE_global.h" 00055 #include "BKE_library.h" 00056 #include "BKE_main.h" 00057 #include "BKE_text.h" 00058 00059 00060 #ifdef WITH_PYTHON 00061 #include "BPY_extern.h" 00062 #endif 00063 00064 /***************/ /* 00065 00066 How Texts should work 00067 -- 00068 A text should relate to a file as follows - 00069 (Text *)->name should be the place where the 00070 file will or has been saved. 00071 00072 (Text *)->flags has the following bits 00073 TXT_ISDIRTY - should always be set if the file in mem. differs from 00074 the file on disk, or if there is no file on disk. 00075 TXT_ISMEM - should always be set if the Text has not been mapped to 00076 a file, in which case (Text *)->name may be NULL or garbage. 00077 TXT_ISEXT - should always be set if the Text is not to be written into 00078 the .blend 00079 TXT_ISSCRIPT - should be set if the user has designated the text 00080 as a script. (NEW: this was unused, but now it is needed by 00081 space handler script links (see header_view3d.c, for example) 00082 00083 ->>> see also: /makesdna/DNA_text_types.h 00084 00085 Display 00086 -- 00087 The st->top determines at what line the top of the text is displayed. 00088 If the user moves the cursor the st containing that cursor should 00089 be popped ... other st's retain their own top location. 00090 00091 Markers 00092 -- 00093 The mrk->flags define the behaviour and relationships between markers. The 00094 upper two bytes are used to hold a group ID, the lower two are normal flags. If 00095 TMARK_EDITALL is set the group ID defines which other markers should be edited. 00096 00097 The mrk->clr field is used to visually group markers where the flags may not 00098 match. A template system, for example, may allow editing of repeating tokens 00099 (in one group) but include other marked positions (in another group) all in the 00100 same template with the same color. 00101 00102 Undo 00103 -- 00104 Undo/Redo works by storing 00105 events in a queue, and a pointer 00106 to the current position in the 00107 queue... 00108 00109 Events are stored using an 00110 arbitrary op-code system 00111 to keep track of 00112 a) the two cursors (normal and selected) 00113 b) input (visible and control (ie backspace)) 00114 00115 input data is stored as its 00116 ASCII value, the opcodes are 00117 then selected to not conflict. 00118 00119 opcodes with data in between are 00120 written at the beginning and end 00121 of the data to allow undo and redo 00122 to simply check the code at the current 00123 undo position 00124 00125 */ /***************/ 00126 00127 /***/ 00128 00129 static void txt_pop_first(Text *text); 00130 static void txt_pop_last(Text *text); 00131 static void txt_undo_add_op(Text *text, int op); 00132 static void txt_undo_add_block(Text *text, int op, const char *buf); 00133 static void txt_delete_line(Text *text, TextLine *line); 00134 static void txt_delete_sel (Text *text); 00135 static void txt_make_dirty (Text *text); 00136 00137 /***/ 00138 00139 static unsigned char undoing; 00140 00141 /* allow to switch off undoing externally */ 00142 void txt_set_undostate(int u) 00143 { 00144 undoing = u; 00145 } 00146 00147 int txt_get_undostate(void) 00148 { 00149 return undoing; 00150 } 00151 00152 static void init_undo_text(Text *text) 00153 { 00154 text->undo_pos= -1; 00155 text->undo_len= TXT_INIT_UNDO; 00156 text->undo_buf= MEM_mallocN(text->undo_len, "undo buf"); 00157 } 00158 00159 void free_text(Text *text) 00160 { 00161 TextLine *tmp; 00162 00163 for (tmp= text->lines.first; tmp; tmp= tmp->next) { 00164 MEM_freeN(tmp->line); 00165 if (tmp->format) 00166 MEM_freeN(tmp->format); 00167 } 00168 00169 BLI_freelistN(&text->lines); 00170 BLI_freelistN(&text->markers); 00171 00172 if(text->name) MEM_freeN(text->name); 00173 MEM_freeN(text->undo_buf); 00174 #ifdef WITH_PYTHON 00175 if (text->compiled) BPY_text_free_code(text); 00176 #endif 00177 } 00178 00179 Text *add_empty_text(const char *name) 00180 { 00181 Main *bmain= G.main; 00182 Text *ta; 00183 TextLine *tmp; 00184 00185 ta= alloc_libblock(&bmain->text, ID_TXT, name); 00186 ta->id.us= 1; 00187 00188 ta->name= NULL; 00189 00190 init_undo_text(ta); 00191 00192 ta->nlines=1; 00193 ta->flags= TXT_ISDIRTY | TXT_ISMEM; 00194 if((U.flag & USER_TXT_TABSTOSPACES_DISABLE)==0) 00195 ta->flags |= TXT_TABSTOSPACES; 00196 00197 ta->lines.first= ta->lines.last= NULL; 00198 ta->markers.first= ta->markers.last= NULL; 00199 00200 tmp= (TextLine*) MEM_mallocN(sizeof(TextLine), "textline"); 00201 tmp->line= (char*) MEM_mallocN(1, "textline_string"); 00202 tmp->format= NULL; 00203 00204 tmp->line[0]=0; 00205 tmp->len= 0; 00206 00207 tmp->next= NULL; 00208 tmp->prev= NULL; 00209 00210 BLI_addhead(&ta->lines, tmp); 00211 00212 ta->curl= ta->lines.first; 00213 ta->curc= 0; 00214 ta->sell= ta->lines.first; 00215 ta->selc= 0; 00216 00217 return ta; 00218 } 00219 00220 /* this function replaces extended ascii characters */ 00221 /* to a valid utf-8 sequences */ 00222 int txt_extended_ascii_as_utf8(char **str) 00223 { 00224 int bad_char, added= 0, i= 0; 00225 int length = strlen(*str); 00226 00227 while ((*str)[i]) { 00228 if((bad_char= BLI_utf8_invalid_byte(*str+i, length)) == -1) 00229 break; 00230 00231 added++; 00232 i+= bad_char + 1; 00233 } 00234 00235 if (added != 0) { 00236 char *newstr = MEM_mallocN(length+added+1, "text_line"); 00237 int mi = 0; 00238 i= 0; 00239 00240 while ((*str)[i]) { 00241 if((bad_char= BLI_utf8_invalid_byte((*str)+i, length)) == -1) { 00242 memcpy(newstr+mi, (*str)+i, length - i + 1); 00243 break; 00244 } 00245 00246 memcpy(newstr+mi, (*str)+i, bad_char); 00247 00248 BLI_str_utf8_from_unicode((*str)[i+bad_char], newstr+mi+bad_char); 00249 i+= bad_char+1; 00250 mi+= bad_char+2; 00251 } 00252 newstr[length+added] = '\0'; 00253 MEM_freeN(*str); 00254 *str = newstr; 00255 } 00256 00257 return added; 00258 } 00259 00260 // this function removes any control characters from 00261 // a textline and fixes invalid utf-8 sequences 00262 00263 static void cleanup_textline(TextLine * tl) 00264 { 00265 int i; 00266 00267 for (i = 0; i < tl->len; i++ ) { 00268 if (tl->line[i] < ' ' && tl->line[i] != '\t') { 00269 memmove(tl->line + i, tl->line + i + 1, tl->len - i); 00270 tl->len--; 00271 i--; 00272 } 00273 } 00274 tl->len+= txt_extended_ascii_as_utf8(&tl->line); 00275 } 00276 00277 int reopen_text(Text *text) 00278 { 00279 FILE *fp; 00280 int i, llen, len; 00281 unsigned char *buffer; 00282 TextLine *tmp; 00283 char str[FILE_MAX]; 00284 struct stat st; 00285 00286 if (!text || !text->name) return 0; 00287 00288 BLI_strncpy(str, text->name, FILE_MAX); 00289 BLI_path_abs(str, G.main->name); 00290 00291 fp= fopen(str, "r"); 00292 if(fp==NULL) return 0; 00293 00294 /* free memory: */ 00295 00296 for (tmp= text->lines.first; tmp; tmp= tmp->next) { 00297 MEM_freeN(tmp->line); 00298 if (tmp->format) MEM_freeN(tmp->format); 00299 } 00300 00301 BLI_freelistN(&text->lines); 00302 00303 text->lines.first= text->lines.last= NULL; 00304 text->curl= text->sell= NULL; 00305 00306 /* clear undo buffer */ 00307 MEM_freeN(text->undo_buf); 00308 init_undo_text(text); 00309 00310 fseek(fp, 0L, SEEK_END); 00311 len= ftell(fp); 00312 fseek(fp, 0L, SEEK_SET); 00313 00314 text->undo_pos= -1; 00315 00316 buffer= MEM_mallocN(len, "text_buffer"); 00317 // under windows fread can return less then len bytes because 00318 // of CR stripping 00319 len = fread(buffer, 1, len, fp); 00320 00321 fclose(fp); 00322 00323 stat(str, &st); 00324 text->mtime= st.st_mtime; 00325 00326 text->nlines=0; 00327 llen=0; 00328 for(i=0; i<len; i++) { 00329 if (buffer[i]=='\n') { 00330 tmp= (TextLine*) MEM_mallocN(sizeof(TextLine), "textline"); 00331 tmp->line= (char*) MEM_mallocN(llen+1, "textline_string"); 00332 tmp->format= NULL; 00333 00334 if(llen) memcpy(tmp->line, &buffer[i-llen], llen); 00335 tmp->line[llen]=0; 00336 tmp->len= llen; 00337 00338 cleanup_textline(tmp); 00339 00340 BLI_addtail(&text->lines, tmp); 00341 text->nlines++; 00342 00343 llen=0; 00344 continue; 00345 } 00346 llen++; 00347 } 00348 00349 if (llen!=0 || text->nlines==0) { 00350 tmp= (TextLine*) MEM_mallocN(sizeof(TextLine), "textline"); 00351 tmp->line= (char*) MEM_mallocN(llen+1, "textline_string"); 00352 tmp->format= NULL; 00353 00354 if(llen) memcpy(tmp->line, &buffer[i-llen], llen); 00355 00356 tmp->line[llen]=0; 00357 tmp->len= llen; 00358 00359 cleanup_textline(tmp); 00360 00361 BLI_addtail(&text->lines, tmp); 00362 text->nlines++; 00363 } 00364 00365 text->curl= text->sell= text->lines.first; 00366 text->curc= text->selc= 0; 00367 00368 MEM_freeN(buffer); 00369 return 1; 00370 } 00371 00372 Text *add_text(const char *file, const char *relpath) 00373 { 00374 Main *bmain= G.main; 00375 FILE *fp; 00376 int i, llen, len; 00377 unsigned char *buffer; 00378 TextLine *tmp; 00379 Text *ta; 00380 char str[FILE_MAX]; 00381 struct stat st; 00382 00383 BLI_strncpy(str, file, FILE_MAX); 00384 if (relpath) /* can be NULL (bg mode) */ 00385 BLI_path_abs(str, relpath); 00386 00387 fp= fopen(str, "r"); 00388 if(fp==NULL) return NULL; 00389 00390 ta= alloc_libblock(&bmain->text, ID_TXT, BLI_path_basename(str)); 00391 ta->id.us= 1; 00392 00393 ta->lines.first= ta->lines.last= NULL; 00394 ta->markers.first= ta->markers.last= NULL; 00395 ta->curl= ta->sell= NULL; 00396 00397 if((U.flag & USER_TXT_TABSTOSPACES_DISABLE)==0) 00398 ta->flags= TXT_TABSTOSPACES; 00399 00400 fseek(fp, 0L, SEEK_END); 00401 len= ftell(fp); 00402 fseek(fp, 0L, SEEK_SET); 00403 00404 ta->name= MEM_mallocN(strlen(file)+1, "text_name"); 00405 strcpy(ta->name, file); 00406 00407 init_undo_text(ta); 00408 00409 buffer= MEM_mallocN(len, "text_buffer"); 00410 // under windows fread can return less then len bytes because 00411 // of CR stripping 00412 len = fread(buffer, 1, len, fp); 00413 00414 fclose(fp); 00415 00416 stat(str, &st); 00417 ta->mtime= st.st_mtime; 00418 00419 ta->nlines=0; 00420 llen=0; 00421 for(i=0; i<len; i++) { 00422 if (buffer[i]=='\n') { 00423 tmp= (TextLine*) MEM_mallocN(sizeof(TextLine), "textline"); 00424 tmp->line= (char*) MEM_mallocN(llen+1, "textline_string"); 00425 tmp->format= NULL; 00426 00427 if(llen) memcpy(tmp->line, &buffer[i-llen], llen); 00428 tmp->line[llen]=0; 00429 tmp->len= llen; 00430 00431 cleanup_textline(tmp); 00432 00433 BLI_addtail(&ta->lines, tmp); 00434 ta->nlines++; 00435 00436 llen=0; 00437 continue; 00438 } 00439 llen++; 00440 } 00441 00442 /* create new line in cases: 00443 - rest of line (if last line in file hasn't got \n terminator). 00444 in this case content of such line would be used to fill text line buffer 00445 - file is empty. in this case new line is needed to start editing from. 00446 - last characted in buffer is \n. in this case new line is needed to 00447 deal with newline at end of file. (see [#28087]) (sergey) */ 00448 if (llen!=0 || ta->nlines==0 || buffer[len-1]=='\n') { 00449 tmp= (TextLine*) MEM_mallocN(sizeof(TextLine), "textline"); 00450 tmp->line= (char*) MEM_mallocN(llen+1, "textline_string"); 00451 tmp->format= NULL; 00452 00453 if(llen) memcpy(tmp->line, &buffer[i-llen], llen); 00454 00455 tmp->line[llen]=0; 00456 tmp->len= llen; 00457 00458 cleanup_textline(tmp); 00459 00460 BLI_addtail(&ta->lines, tmp); 00461 ta->nlines++; 00462 } 00463 00464 ta->curl= ta->sell= ta->lines.first; 00465 ta->curc= ta->selc= 0; 00466 00467 MEM_freeN(buffer); 00468 00469 return ta; 00470 } 00471 00472 Text *copy_text(Text *ta) 00473 { 00474 Text *tan; 00475 TextLine *line, *tmp; 00476 00477 tan= copy_libblock(&ta->id); 00478 00479 /* file name can be NULL */ 00480 if(ta->name) { 00481 tan->name= MEM_mallocN(strlen(ta->name)+1, "text_name"); 00482 strcpy(tan->name, ta->name); 00483 } 00484 else { 00485 tan->name= NULL; 00486 } 00487 00488 tan->flags = ta->flags | TXT_ISDIRTY; 00489 00490 tan->lines.first= tan->lines.last= NULL; 00491 tan->markers.first= tan->markers.last= NULL; 00492 tan->curl= tan->sell= NULL; 00493 00494 tan->nlines= ta->nlines; 00495 00496 line= ta->lines.first; 00497 /* Walk down, reconstructing */ 00498 while (line) { 00499 tmp= (TextLine*) MEM_mallocN(sizeof(TextLine), "textline"); 00500 tmp->line= MEM_mallocN(line->len+1, "textline_string"); 00501 tmp->format= NULL; 00502 00503 strcpy(tmp->line, line->line); 00504 00505 tmp->len= line->len; 00506 00507 BLI_addtail(&tan->lines, tmp); 00508 00509 line= line->next; 00510 } 00511 00512 tan->curl= tan->sell= tan->lines.first; 00513 tan->curc= tan->selc= 0; 00514 00515 init_undo_text(tan); 00516 00517 return tan; 00518 } 00519 00520 void unlink_text(Main *bmain, Text *text) 00521 { 00522 bScreen *scr; 00523 ScrArea *area; 00524 SpaceLink *sl; 00525 Object *ob; 00526 bController *cont; 00527 bConstraint *con; 00528 short update; 00529 00530 for(ob=bmain->object.first; ob; ob=ob->id.next) { 00531 /* game controllers */ 00532 for(cont=ob->controllers.first; cont; cont=cont->next) { 00533 if(cont->type==CONT_PYTHON) { 00534 bPythonCont *pc; 00535 00536 pc= cont->data; 00537 if(pc->text==text) pc->text= NULL; 00538 } 00539 } 00540 00541 /* pyconstraints */ 00542 update = 0; 00543 00544 if(ob->type==OB_ARMATURE && ob->pose) { 00545 bPoseChannel *pchan; 00546 for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) { 00547 for(con = pchan->constraints.first; con; con=con->next) { 00548 if(con->type==CONSTRAINT_TYPE_PYTHON) { 00549 bPythonConstraint *data = con->data; 00550 if (data->text==text) data->text = NULL; 00551 update = 1; 00552 00553 } 00554 } 00555 } 00556 } 00557 00558 for(con = ob->constraints.first; con; con=con->next) { 00559 if(con->type==CONSTRAINT_TYPE_PYTHON) { 00560 bPythonConstraint *data = con->data; 00561 if (data->text==text) data->text = NULL; 00562 update = 1; 00563 } 00564 } 00565 00566 if(update) 00567 DAG_id_tag_update(&ob->id, OB_RECALC_DATA); 00568 } 00569 00570 /* pynodes */ 00571 // XXX nodeDynamicUnlinkText(&text->id); 00572 00573 /* text space */ 00574 for(scr= bmain->screen.first; scr; scr= scr->id.next) { 00575 for(area= scr->areabase.first; area; area= area->next) { 00576 for(sl= area->spacedata.first; sl; sl= sl->next) { 00577 if(sl->spacetype==SPACE_TEXT) { 00578 SpaceText *st= (SpaceText*) sl; 00579 00580 if(st->text==text) { 00581 st->text= NULL; 00582 st->top= 0; 00583 } 00584 } 00585 } 00586 } 00587 } 00588 00589 text->id.us= 0; 00590 } 00591 00592 void clear_text(Text *text) /* called directly from rna */ 00593 { 00594 int oldstate; 00595 00596 oldstate = txt_get_undostate( ); 00597 txt_set_undostate( 1 ); 00598 txt_sel_all( text ); 00599 txt_delete_sel(text); 00600 txt_set_undostate( oldstate ); 00601 00602 txt_make_dirty(text); 00603 } 00604 00605 void write_text(Text *text, const char *str) /* called directly from rna */ 00606 { 00607 int oldstate; 00608 00609 oldstate = txt_get_undostate( ); 00610 txt_insert_buf( text, str ); 00611 txt_move_eof( text, 0 ); 00612 txt_set_undostate( oldstate ); 00613 00614 txt_make_dirty(text); 00615 } 00616 00617 /*****************************/ 00618 /* Editing utility functions */ 00619 /*****************************/ 00620 00621 static void make_new_line (TextLine *line, char *newline) 00622 { 00623 if (line->line) MEM_freeN(line->line); 00624 if (line->format) MEM_freeN(line->format); 00625 00626 line->line= newline; 00627 line->len= strlen(newline); 00628 line->format= NULL; 00629 } 00630 00631 static TextLine *txt_new_line(const char *str) 00632 { 00633 TextLine *tmp; 00634 00635 if(!str) str= ""; 00636 00637 tmp= (TextLine *) MEM_mallocN(sizeof(TextLine), "textline"); 00638 tmp->line= MEM_mallocN(strlen(str)+1, "textline_string"); 00639 tmp->format= NULL; 00640 00641 strcpy(tmp->line, str); 00642 00643 tmp->len= strlen(str); 00644 tmp->next= tmp->prev= NULL; 00645 00646 return tmp; 00647 } 00648 00649 static TextLine *txt_new_linen(const char *str, int n) 00650 { 00651 TextLine *tmp; 00652 00653 tmp= (TextLine *) MEM_mallocN(sizeof(TextLine), "textline"); 00654 tmp->line= MEM_mallocN(n+1, "textline_string"); 00655 tmp->format= NULL; 00656 00657 BLI_strncpy(tmp->line, (str)? str: "", n+1); 00658 00659 tmp->len= strlen(tmp->line); 00660 tmp->next= tmp->prev= NULL; 00661 00662 return tmp; 00663 } 00664 00665 void txt_clean_text (Text *text) 00666 { 00667 TextLine **top, **bot; 00668 00669 if (!text) return; 00670 00671 if (!text->lines.first) { 00672 if (text->lines.last) text->lines.first= text->lines.last; 00673 else text->lines.first= text->lines.last= txt_new_line(NULL); 00674 } 00675 00676 if (!text->lines.last) text->lines.last= text->lines.first; 00677 00678 top= (TextLine **) &text->lines.first; 00679 bot= (TextLine **) &text->lines.last; 00680 00681 while ((*top)->prev) *top= (*top)->prev; 00682 while ((*bot)->next) *bot= (*bot)->next; 00683 00684 if(!text->curl) { 00685 if(text->sell) text->curl= text->sell; 00686 else text->curl= text->lines.first; 00687 text->curc= 0; 00688 } 00689 00690 if(!text->sell) { 00691 text->sell= text->curl; 00692 text->selc= 0; 00693 } 00694 } 00695 00696 int txt_get_span (TextLine *from, TextLine *to) 00697 { 00698 int ret=0; 00699 TextLine *tmp= from; 00700 00701 if (!to || !from) return 0; 00702 if (from==to) return 0; 00703 00704 /* Look forwards */ 00705 while (tmp) { 00706 if (tmp == to) return ret; 00707 ret++; 00708 tmp= tmp->next; 00709 } 00710 00711 /* Look backwards */ 00712 if (!tmp) { 00713 tmp= from; 00714 ret=0; 00715 while(tmp) { 00716 if (tmp == to) break; 00717 ret--; 00718 tmp= tmp->prev; 00719 } 00720 if(!tmp) ret=0; 00721 } 00722 00723 return ret; 00724 } 00725 00726 static void txt_make_dirty (Text *text) 00727 { 00728 text->flags |= TXT_ISDIRTY; 00729 #ifdef WITH_PYTHON 00730 if (text->compiled) BPY_text_free_code(text); 00731 #endif 00732 } 00733 00734 /* 0:whitespace, 1:punct, 2:alphanumeric */ 00735 static short txt_char_type(unsigned int ch) 00736 { 00737 if (iswspace(ch)) return 0; 00738 if (iswalpha(ch) || iswdigit(ch)) return 2; 00739 return 1; 00740 } 00741 00742 /****************************/ 00743 /* Cursor utility functions */ 00744 /****************************/ 00745 00746 static void txt_curs_cur (Text *text, TextLine ***linep, int **charp) 00747 { 00748 *linep= &text->curl; *charp= &text->curc; 00749 } 00750 00751 static void txt_curs_sel (Text *text, TextLine ***linep, int **charp) 00752 { 00753 *linep= &text->sell; *charp= &text->selc; 00754 } 00755 00756 static void txt_curs_first (Text *text, TextLine **linep, int *charp) 00757 { 00758 if (text->curl==text->sell) { 00759 *linep= text->curl; 00760 if (text->curc<text->selc) *charp= text->curc; 00761 else *charp= text->selc; 00762 } else if (txt_get_span(text->lines.first, text->curl)<txt_get_span(text->lines.first, text->sell)) { 00763 *linep= text->curl; 00764 *charp= text->curc; 00765 } else { 00766 *linep= text->sell; 00767 *charp= text->selc; 00768 } 00769 } 00770 00771 /*****************************/ 00772 /* Cursor movement functions */ 00773 /*****************************/ 00774 00775 int txt_utf8_offset_to_index(char *str, int offset) 00776 { 00777 int index= 0, pos= 0; 00778 while (pos != offset) { 00779 pos += BLI_str_utf8_size(str + pos); 00780 index++; 00781 } 00782 return index; 00783 } 00784 00785 int txt_utf8_index_to_offset(char *str, int index) 00786 { 00787 int offset= 0, pos= 0; 00788 while (pos != index) { 00789 offset += BLI_str_utf8_size(str + offset); 00790 pos++; 00791 } 00792 return offset; 00793 } 00794 00795 /* returns the real number of characters in string */ 00796 /* not the same as BLI_strlen_utf8, which returns length for wide characters */ 00797 static int txt_utf8_len(const char *src) 00798 { 00799 int len; 00800 00801 for (len=0; *src; len++) { 00802 src += BLI_str_utf8_size(src); 00803 } 00804 00805 return len; 00806 } 00807 00808 void txt_move_up(Text *text, short sel) 00809 { 00810 TextLine **linep; 00811 int *charp, old; 00812 00813 if (!text) return; 00814 if(sel) txt_curs_sel(text, &linep, &charp); 00815 else { txt_pop_first(text); txt_curs_cur(text, &linep, &charp); } 00816 if (!*linep) return; 00817 old= *charp; 00818 00819 if((*linep)->prev) { 00820 int index = txt_utf8_offset_to_index((*linep)->line, *charp); 00821 *linep= (*linep)->prev; 00822 if (index > txt_utf8_len((*linep)->line)) *charp= (*linep)->len; 00823 else *charp= txt_utf8_index_to_offset((*linep)->line, index); 00824 00825 if(!undoing) 00826 txt_undo_add_op(text, sel?UNDO_SUP:UNDO_CUP); 00827 } else { 00828 txt_move_bol(text, sel); 00829 } 00830 00831 if(!sel) txt_pop_sel(text); 00832 } 00833 00834 void txt_move_down(Text *text, short sel) 00835 { 00836 TextLine **linep; 00837 int *charp, old; 00838 00839 if (!text) return; 00840 if(sel) txt_curs_sel(text, &linep, &charp); 00841 else { txt_pop_last(text); txt_curs_cur(text, &linep, &charp); } 00842 if (!*linep) return; 00843 old= *charp; 00844 00845 if((*linep)->next) { 00846 int index = txt_utf8_offset_to_index((*linep)->line, *charp); 00847 *linep= (*linep)->next; 00848 if (index > txt_utf8_len((*linep)->line)) *charp= (*linep)->len; 00849 else *charp= txt_utf8_index_to_offset((*linep)->line, index); 00850 00851 if(!undoing) 00852 txt_undo_add_op(text, sel?UNDO_SDOWN:UNDO_CDOWN); 00853 } else { 00854 txt_move_eol(text, sel); 00855 } 00856 00857 if(!sel) txt_pop_sel(text); 00858 } 00859 00860 void txt_move_left(Text *text, short sel) 00861 { 00862 TextLine **linep; 00863 int *charp, oundoing= undoing; 00864 int tabsize= 0, i= 0; 00865 00866 if (!text) return; 00867 if(sel) txt_curs_sel(text, &linep, &charp); 00868 else { txt_pop_first(text); txt_curs_cur(text, &linep, &charp); } 00869 if (!*linep) return; 00870 00871 undoing= 1; 00872 00873 if (*charp== 0) { 00874 if ((*linep)->prev) { 00875 txt_move_up(text, sel); 00876 *charp= (*linep)->len; 00877 } 00878 } 00879 else { 00880 // do nice left only if there are only spaces 00881 // TXT_TABSIZE hardcoded in DNA_text_types.h 00882 if (text->flags & TXT_TABSTOSPACES) { 00883 tabsize= (*charp < TXT_TABSIZE) ? *charp : TXT_TABSIZE; 00884 00885 for (i=0; i<(*charp); i++) 00886 if ((*linep)->line[i] != ' ') { 00887 tabsize= 0; 00888 break; 00889 } 00890 00891 // if in the middle of the space-tab 00892 if (tabsize && (*charp) % TXT_TABSIZE != 0) 00893 tabsize= ((*charp) % TXT_TABSIZE); 00894 } 00895 00896 if (tabsize) 00897 (*charp)-= tabsize; 00898 else { 00899 const char *prev= BLI_str_prev_char_utf8((*linep)->line + *charp); 00900 *charp= prev - (*linep)->line; 00901 } 00902 } 00903 00904 undoing= oundoing; 00905 if(!undoing) txt_undo_add_op(text, sel?UNDO_SLEFT:UNDO_CLEFT); 00906 00907 if(!sel) txt_pop_sel(text); 00908 } 00909 00910 void txt_move_right(Text *text, short sel) 00911 { 00912 TextLine **linep; 00913 int *charp, oundoing= undoing, do_tab= 0, i; 00914 00915 if (!text) return; 00916 if(sel) txt_curs_sel(text, &linep, &charp); 00917 else { txt_pop_last(text); txt_curs_cur(text, &linep, &charp); } 00918 if (!*linep) return; 00919 00920 undoing= 1; 00921 00922 if (*charp== (*linep)->len) { 00923 if ((*linep)->next) { 00924 txt_move_down(text, sel); 00925 *charp= 0; 00926 } 00927 } 00928 else { 00929 // do nice right only if there are only spaces 00930 // spaces hardcoded in DNA_text_types.h 00931 if (text->flags & TXT_TABSTOSPACES && (*linep)->line[*charp]== ' ') { 00932 do_tab= 1; 00933 for (i=0; i<*charp; i++) 00934 if ((*linep)->line[i]!= ' ') { 00935 do_tab= 0; 00936 break; 00937 } 00938 } 00939 00940 if (do_tab) { 00941 int tabsize= (*charp) % TXT_TABSIZE + 1; 00942 for (i=*charp+1; (*linep)->line[i]==' ' && tabsize<TXT_TABSIZE; i++) 00943 tabsize++; 00944 (*charp)= i; 00945 } 00946 else (*charp)+= BLI_str_utf8_size((*linep)->line + *charp); 00947 } 00948 00949 undoing= oundoing; 00950 if(!undoing) txt_undo_add_op(text, sel?UNDO_SRIGHT:UNDO_CRIGHT); 00951 00952 if(!sel) txt_pop_sel(text); 00953 } 00954 00955 void txt_jump_left(Text *text, short sel) 00956 { 00957 TextLine **linep, *oldl; 00958 int *charp, oldc, count, i; 00959 unsigned char oldu; 00960 00961 if (!text) return; 00962 if(sel) txt_curs_sel(text, &linep, &charp); 00963 else { txt_pop_first(text); txt_curs_cur(text, &linep, &charp); } 00964 if (!*linep) return; 00965 00966 oldl= *linep; 00967 oldc= *charp; 00968 oldu= undoing; 00969 undoing= 1; /* Don't push individual moves to undo stack */ 00970 00971 count= 0; 00972 for (i=0; i<3; i++) { 00973 if (count < 2) { 00974 while (*charp>0) { 00975 char *sym= BLI_str_prev_char_utf8((*linep)->line + *charp); 00976 if (txt_char_type(BLI_str_utf8_as_unicode(sym))==i) { 00977 txt_move_left(text, sel); 00978 count++; 00979 } else break; 00980 } 00981 } 00982 } 00983 if (count==0) txt_move_left(text, sel); 00984 00985 undoing= oldu; 00986 if(!undoing) txt_undo_add_toop(text, sel?UNDO_STO:UNDO_CTO, txt_get_span(text->lines.first, oldl), oldc, txt_get_span(text->lines.first, *linep), (unsigned short)*charp); 00987 } 00988 00989 void txt_jump_right(Text *text, short sel) 00990 { 00991 TextLine **linep, *oldl; 00992 int *charp, oldc, count, i; 00993 unsigned char oldu; 00994 00995 if (!text) return; 00996 if(sel) txt_curs_sel(text, &linep, &charp); 00997 else { txt_pop_last(text); txt_curs_cur(text, &linep, &charp); } 00998 if (!*linep) return; 00999 01000 oldl= *linep; 01001 oldc= *charp; 01002 oldu= undoing; 01003 undoing= 1; /* Don't push individual moves to undo stack */ 01004 01005 count= 0; 01006 for (i=0; i<3; i++) { 01007 if (count < 2) { 01008 while (*charp<(*linep)->len) { 01009 char *sym= (*linep)->line + *charp; 01010 if (txt_char_type(BLI_str_utf8_as_unicode(sym))==i) { 01011 txt_move_right(text, sel); 01012 count++; 01013 } else break; 01014 } 01015 } 01016 } 01017 if (count==0) txt_move_right(text, sel); 01018 01019 undoing= oldu; 01020 if(!undoing) txt_undo_add_toop(text, sel?UNDO_STO:UNDO_CTO, txt_get_span(text->lines.first, oldl), oldc, txt_get_span(text->lines.first, *linep), (unsigned short)*charp); 01021 } 01022 01023 void txt_move_bol (Text *text, short sel) 01024 { 01025 TextLine **linep; 01026 int *charp, old; 01027 01028 if (!text) return; 01029 if(sel) txt_curs_sel(text, &linep, &charp); 01030 else txt_curs_cur(text, &linep, &charp); 01031 if (!*linep) return; 01032 old= *charp; 01033 01034 *charp= 0; 01035 01036 if(!sel) txt_pop_sel(text); 01037 if(!undoing) txt_undo_add_toop(text, sel?UNDO_STO:UNDO_CTO, txt_get_span(text->lines.first, *linep), old, txt_get_span(text->lines.first, *linep), (unsigned short)*charp); 01038 } 01039 01040 void txt_move_eol (Text *text, short sel) 01041 { 01042 TextLine **linep; 01043 int *charp, old; 01044 01045 if (!text) return; 01046 if(sel) txt_curs_sel(text, &linep, &charp); 01047 else txt_curs_cur(text, &linep, &charp); 01048 if (!*linep) return; 01049 old= *charp; 01050 01051 *charp= (*linep)->len; 01052 01053 if(!sel) txt_pop_sel(text); 01054 if(!undoing) txt_undo_add_toop(text, sel?UNDO_STO:UNDO_CTO, txt_get_span(text->lines.first, *linep), old, txt_get_span(text->lines.first, *linep), (unsigned short)*charp); 01055 } 01056 01057 void txt_move_bof (Text *text, short sel) 01058 { 01059 TextLine **linep; 01060 int *charp, old; 01061 01062 if (!text) return; 01063 if(sel) txt_curs_sel(text, &linep, &charp); 01064 else txt_curs_cur(text, &linep, &charp); 01065 if (!*linep) return; 01066 old= *charp; 01067 01068 *linep= text->lines.first; 01069 *charp= 0; 01070 01071 if(!sel) txt_pop_sel(text); 01072 if(!undoing) txt_undo_add_toop(text, sel?UNDO_STO:UNDO_CTO, txt_get_span(text->lines.first, *linep), old, txt_get_span(text->lines.first, *linep), (unsigned short)*charp); 01073 } 01074 01075 void txt_move_eof (Text *text, short sel) 01076 { 01077 TextLine **linep; 01078 int *charp, old; 01079 01080 if (!text) return; 01081 if(sel) txt_curs_sel(text, &linep, &charp); 01082 else txt_curs_cur(text, &linep, &charp); 01083 if (!*linep) return; 01084 old= *charp; 01085 01086 *linep= text->lines.last; 01087 *charp= (*linep)->len; 01088 01089 if(!sel) txt_pop_sel(text); 01090 if(!undoing) txt_undo_add_toop(text, sel?UNDO_STO:UNDO_CTO, txt_get_span(text->lines.first, *linep), old, txt_get_span(text->lines.first, *linep), (unsigned short)*charp); 01091 } 01092 01093 void txt_move_toline (Text *text, unsigned int line, short sel) 01094 { 01095 txt_move_to(text, line, 0, sel); 01096 } 01097 01098 /* Moves to a certain byte in a line, not a certain utf8-character! */ 01099 void txt_move_to (Text *text, unsigned int line, unsigned int ch, short sel) 01100 { 01101 TextLine **linep, *oldl; 01102 int *charp, oldc; 01103 unsigned int i; 01104 01105 if (!text) return; 01106 if(sel) txt_curs_sel(text, &linep, &charp); 01107 else txt_curs_cur(text, &linep, &charp); 01108 if (!*linep) return; 01109 oldc= *charp; 01110 oldl= *linep; 01111 01112 *linep= text->lines.first; 01113 for (i=0; i<line; i++) { 01114 if ((*linep)->next) *linep= (*linep)->next; 01115 else break; 01116 } 01117 if (ch>(unsigned int)((*linep)->len)) 01118 ch= (unsigned int)((*linep)->len); 01119 *charp= ch; 01120 01121 if(!sel) txt_pop_sel(text); 01122 if(!undoing) txt_undo_add_toop(text, sel?UNDO_STO:UNDO_CTO, txt_get_span(text->lines.first, oldl), oldc, txt_get_span(text->lines.first, *linep), (unsigned short)*charp); 01123 } 01124 01125 /****************************/ 01126 /* Text selection functions */ 01127 /****************************/ 01128 01129 static void txt_curs_swap (Text *text) 01130 { 01131 TextLine *tmpl; 01132 int tmpc; 01133 01134 tmpl= text->curl; 01135 text->curl= text->sell; 01136 text->sell= tmpl; 01137 01138 tmpc= text->curc; 01139 text->curc= text->selc; 01140 text->selc= tmpc; 01141 01142 if(!undoing) txt_undo_add_op(text, UNDO_SWAP); 01143 } 01144 01145 static void txt_pop_first (Text *text) 01146 { 01147 01148 if (txt_get_span(text->curl, text->sell)<0 || 01149 (text->curl==text->sell && text->curc>text->selc)) { 01150 txt_curs_swap(text); 01151 } 01152 01153 if(!undoing) txt_undo_add_toop(text, UNDO_STO, 01154 txt_get_span(text->lines.first, text->sell), 01155 text->selc, 01156 txt_get_span(text->lines.first, text->curl), 01157 text->curc); 01158 01159 txt_pop_sel(text); 01160 } 01161 01162 static void txt_pop_last (Text *text) 01163 { 01164 if (txt_get_span(text->curl, text->sell)>0 || 01165 (text->curl==text->sell && text->curc<text->selc)) { 01166 txt_curs_swap(text); 01167 } 01168 01169 if(!undoing) txt_undo_add_toop(text, UNDO_STO, 01170 txt_get_span(text->lines.first, text->sell), 01171 text->selc, 01172 txt_get_span(text->lines.first, text->curl), 01173 text->curc); 01174 01175 txt_pop_sel(text); 01176 } 01177 01178 /* never used: CVS 1.19 */ 01179 /* static void txt_pop_selr (Text *text) */ 01180 01181 void txt_pop_sel (Text *text) 01182 { 01183 text->sell= text->curl; 01184 text->selc= text->curc; 01185 } 01186 01187 void txt_order_cursors(Text *text) 01188 { 01189 if (!text) return; 01190 if (!text->curl) return; 01191 if (!text->sell) return; 01192 01193 /* Flip so text->curl is before text->sell */ 01194 if (txt_get_span(text->curl, text->sell)<0 || 01195 (text->curl==text->sell && text->curc>text->selc)) 01196 txt_curs_swap(text); 01197 } 01198 01199 int txt_has_sel(Text *text) 01200 { 01201 return ((text->curl!=text->sell) || (text->curc!=text->selc)); 01202 } 01203 01204 static void txt_delete_sel (Text *text) 01205 { 01206 TextLine *tmpl; 01207 TextMarker *mrk; 01208 char *buf; 01209 int move, lineno; 01210 01211 if (!text) return; 01212 if (!text->curl) return; 01213 if (!text->sell) return; 01214 01215 if (!txt_has_sel(text)) return; 01216 01217 txt_order_cursors(text); 01218 01219 if(!undoing) { 01220 buf= txt_sel_to_buf(text); 01221 txt_undo_add_block(text, UNDO_DBLOCK, buf); 01222 MEM_freeN(buf); 01223 } 01224 01225 buf= MEM_mallocN(text->curc+(text->sell->len - text->selc)+1, "textline_string"); 01226 01227 if (text->curl != text->sell) { 01228 txt_clear_marker_region(text, text->curl, text->curc, text->curl->len, 0, 0); 01229 move= txt_get_span(text->curl, text->sell); 01230 } else { 01231 mrk= txt_find_marker_region(text, text->curl, text->curc, text->selc, 0, 0); 01232 if (mrk && (mrk->start > text->curc || mrk->end < text->selc)) 01233 txt_clear_marker_region(text, text->curl, text->curc, text->selc, 0, 0); 01234 move= 0; 01235 } 01236 01237 mrk= txt_find_marker_region(text, text->sell, text->selc-1, text->sell->len, 0, 0); 01238 if (mrk) { 01239 lineno= mrk->lineno; 01240 do { 01241 mrk->lineno -= move; 01242 if (mrk->start > text->curc) mrk->start -= text->selc - text->curc; 01243 mrk->end -= text->selc - text->curc; 01244 mrk= mrk->next; 01245 } while (mrk && mrk->lineno==lineno); 01246 } 01247 01248 strncpy(buf, text->curl->line, text->curc); 01249 strcpy(buf+text->curc, text->sell->line + text->selc); 01250 buf[text->curc+(text->sell->len - text->selc)]=0; 01251 01252 make_new_line(text->curl, buf); 01253 01254 tmpl= text->sell; 01255 while (tmpl != text->curl) { 01256 tmpl= tmpl->prev; 01257 if (!tmpl) break; 01258 01259 txt_delete_line(text, tmpl->next); 01260 } 01261 01262 text->sell= text->curl; 01263 text->selc= text->curc; 01264 } 01265 01266 void txt_sel_all (Text *text) 01267 { 01268 if (!text) return; 01269 01270 text->curl= text->lines.first; 01271 text->curc= 0; 01272 01273 text->sell= text->lines.last; 01274 text->selc= text->sell->len; 01275 } 01276 01277 void txt_sel_line (Text *text) 01278 { 01279 if (!text) return; 01280 if (!text->curl) return; 01281 01282 text->curc= 0; 01283 text->sell= text->curl; 01284 text->selc= text->sell->len; 01285 } 01286 01287 /***************************/ 01288 /* Cut and paste functions */ 01289 /***************************/ 01290 01291 char *txt_to_buf (Text *text) 01292 { 01293 int length; 01294 TextLine *tmp, *linef, *linel; 01295 int charf, charl; 01296 char *buf; 01297 01298 if (!text) return NULL; 01299 if (!text->curl) return NULL; 01300 if (!text->sell) return NULL; 01301 if (!text->lines.first) return NULL; 01302 01303 linef= text->lines.first; 01304 charf= 0; 01305 01306 linel= text->lines.last; 01307 charl= linel->len; 01308 01309 if (linef == text->lines.last) { 01310 length= charl-charf; 01311 01312 buf= MEM_mallocN(length+2, "text buffer"); 01313 01314 BLI_strncpy(buf, linef->line + charf, length+1); 01315 buf[length]=0; 01316 } else { 01317 length= linef->len - charf; 01318 length+= charl; 01319 length+= 2; /* For the 2 '\n' */ 01320 01321 tmp= linef->next; 01322 while (tmp && tmp!= linel) { 01323 length+= tmp->len+1; 01324 tmp= tmp->next; 01325 } 01326 01327 buf= MEM_mallocN(length+1, "cut buffer"); 01328 01329 strncpy(buf, linef->line + charf, linef->len-charf); 01330 length= linef->len - charf; 01331 01332 buf[length++]='\n'; 01333 01334 tmp= linef->next; 01335 while (tmp && tmp!=linel) { 01336 strncpy(buf+length, tmp->line, tmp->len); 01337 length+= tmp->len; 01338 01339 buf[length++]='\n'; 01340 01341 tmp= tmp->next; 01342 } 01343 strncpy(buf+length, linel->line, charl); 01344 length+= charl; 01345 01346 /* python compiler wants an empty end line */ 01347 buf[length++]='\n'; 01348 buf[length]=0; 01349 } 01350 01351 return buf; 01352 } 01353 01354 int txt_find_string(Text *text, const char *findstr, int wrap, int match_case) 01355 { 01356 TextLine *tl, *startl; 01357 char *s= NULL; 01358 01359 if (!text || !text->curl || !text->sell) return 0; 01360 01361 txt_order_cursors(text); 01362 01363 tl= startl= text->sell; 01364 01365 if(match_case) s= strstr(&tl->line[text->selc], findstr); 01366 else s= BLI_strcasestr(&tl->line[text->selc], findstr); 01367 while (!s) { 01368 tl= tl->next; 01369 if (!tl) { 01370 if (wrap) 01371 tl= text->lines.first; 01372 else 01373 break; 01374 } 01375 01376 if(match_case) s= strstr(tl->line, findstr); 01377 else s= BLI_strcasestr(tl->line, findstr); 01378 if (tl==startl) 01379 break; 01380 } 01381 01382 if (s) { 01383 int newl= txt_get_span(text->lines.first, tl); 01384 int newc= (int)(s-tl->line); 01385 txt_move_to(text, newl, newc, 0); 01386 txt_move_to(text, newl, newc + strlen(findstr), 1); 01387 return 1; 01388 } else 01389 return 0; 01390 } 01391 01392 char *txt_sel_to_buf (Text *text) 01393 { 01394 char *buf; 01395 int length=0; 01396 TextLine *tmp, *linef, *linel; 01397 int charf, charl; 01398 01399 if (!text) return NULL; 01400 if (!text->curl) return NULL; 01401 if (!text->sell) return NULL; 01402 01403 if (text->curl==text->sell) { 01404 linef= linel= text->curl; 01405 01406 if (text->curc < text->selc) { 01407 charf= text->curc; 01408 charl= text->selc; 01409 } else{ 01410 charf= text->selc; 01411 charl= text->curc; 01412 } 01413 } else if (txt_get_span(text->curl, text->sell)<0) { 01414 linef= text->sell; 01415 linel= text->curl; 01416 01417 charf= text->selc; 01418 charl= text->curc; 01419 } else { 01420 linef= text->curl; 01421 linel= text->sell; 01422 01423 charf= text->curc; 01424 charl= text->selc; 01425 } 01426 01427 if (linef == linel) { 01428 length= charl-charf; 01429 01430 buf= MEM_mallocN(length+1, "sel buffer"); 01431 01432 BLI_strncpy(buf, linef->line + charf, length+1); 01433 } else { 01434 length+= linef->len - charf; 01435 length+= charl; 01436 length++; /* For the '\n' */ 01437 01438 tmp= linef->next; 01439 while (tmp && tmp!= linel) { 01440 length+= tmp->len+1; 01441 tmp= tmp->next; 01442 } 01443 01444 buf= MEM_mallocN(length+1, "sel buffer"); 01445 01446 strncpy(buf, linef->line+ charf, linef->len-charf); 01447 length= linef->len-charf; 01448 01449 buf[length++]='\n'; 01450 01451 tmp= linef->next; 01452 while (tmp && tmp!=linel) { 01453 strncpy(buf+length, tmp->line, tmp->len); 01454 length+= tmp->len; 01455 01456 buf[length++]='\n'; 01457 01458 tmp= tmp->next; 01459 } 01460 strncpy(buf+length, linel->line, charl); 01461 length+= charl; 01462 01463 buf[length]=0; 01464 } 01465 01466 return buf; 01467 } 01468 01469 static void txt_shift_markers(Text *text, int lineno, int count) 01470 { 01471 TextMarker *marker; 01472 01473 for (marker=text->markers.first; marker; marker= marker->next) 01474 if (marker->lineno>=lineno) { 01475 marker->lineno+= count; 01476 } 01477 } 01478 01479 void txt_insert_buf(Text *text, const char *in_buffer) 01480 { 01481 int l=0, u, len, lineno= -1, count= 0; 01482 size_t i=0, j; 01483 TextLine *add; 01484 char *buffer; 01485 01486 if (!text) return; 01487 if (!in_buffer) return; 01488 01489 txt_delete_sel(text); 01490 01491 len= strlen(in_buffer); 01492 buffer= BLI_strdupn(in_buffer, len); 01493 len+= txt_extended_ascii_as_utf8(&buffer); 01494 01495 if(!undoing) txt_undo_add_block(text, UNDO_IBLOCK, buffer); 01496 01497 u= undoing; 01498 undoing= 1; 01499 01500 /* Read the first line (or as close as possible */ 01501 while (buffer[i] && buffer[i]!='\n') 01502 txt_add_raw_char(text, BLI_str_utf8_as_unicode_step(buffer, &i)); 01503 01504 if (buffer[i]=='\n') txt_split_curline(text); 01505 else { undoing = u; MEM_freeN(buffer); return; } 01506 i++; 01507 01508 /* Read as many full lines as we can */ 01509 lineno= txt_get_span(text->lines.first, text->curl); 01510 01511 while (i<len) { 01512 l=0; 01513 01514 while (buffer[i] && buffer[i]!='\n') { 01515 i++; l++; 01516 } 01517 01518 if(buffer[i]=='\n') { 01519 add= txt_new_linen(buffer +(i-l), l); 01520 BLI_insertlinkbefore(&text->lines, text->curl, add); 01521 i++; 01522 count++; 01523 } else { 01524 if(count) { 01525 txt_shift_markers(text, lineno, count); 01526 count= 0; 01527 } 01528 01529 for (j= i-l; j<i && j<len; ) 01530 txt_add_raw_char(text, BLI_str_utf8_as_unicode_step(buffer, &j)); 01531 break; 01532 } 01533 } 01534 01535 MEM_freeN(buffer); 01536 01537 if(count) { 01538 txt_shift_markers(text, lineno, count); 01539 } 01540 01541 undoing= u; 01542 } 01543 01544 /******************/ 01545 /* Undo functions */ 01546 /******************/ 01547 01548 static int max_undo_test(Text *text, int x) 01549 { 01550 while (text->undo_pos+x >= text->undo_len) { 01551 if(text->undo_len*2 > TXT_MAX_UNDO) { 01552 /* XXX error("Undo limit reached, buffer cleared\n"); */ 01553 MEM_freeN(text->undo_buf); 01554 init_undo_text(text); 01555 return 0; 01556 } else { 01557 void *tmp= text->undo_buf; 01558 text->undo_buf= MEM_callocN(text->undo_len*2, "undo buf"); 01559 memcpy(text->undo_buf, tmp, text->undo_len); 01560 text->undo_len*=2; 01561 MEM_freeN(tmp); 01562 } 01563 } 01564 01565 return 1; 01566 } 01567 01568 static void dump_buffer(Text *text) 01569 { 01570 int i= 0; 01571 01572 while (i++<text->undo_pos) printf("%d: %d %c\n", i, text->undo_buf[i], text->undo_buf[i]); 01573 } 01574 01575 void txt_print_undo(Text *text) 01576 { 01577 int i= 0; 01578 int op; 01579 const char *ops; 01580 int linep, charp; 01581 01582 dump_buffer(text); 01583 01584 printf ("---< Undo Buffer >---\n"); 01585 01586 printf ("UndoPosition is %d\n", text->undo_pos); 01587 01588 while (i<=text->undo_pos) { 01589 op= text->undo_buf[i]; 01590 01591 if (op==UNDO_CLEFT) { 01592 ops= "Cursor left"; 01593 } else if (op==UNDO_CRIGHT) { 01594 ops= "Cursor right"; 01595 } else if (op==UNDO_CUP) { 01596 ops= "Cursor up"; 01597 } else if (op==UNDO_CDOWN) { 01598 ops= "Cursor down"; 01599 } else if (op==UNDO_SLEFT) { 01600 ops= "Selection left"; 01601 } else if (op==UNDO_SRIGHT) { 01602 ops= "Selection right"; 01603 } else if (op==UNDO_SUP) { 01604 ops= "Selection up"; 01605 } else if (op==UNDO_SDOWN) { 01606 ops= "Selection down"; 01607 } else if (op==UNDO_STO) { 01608 ops= "Selection "; 01609 } else if (op==UNDO_CTO) { 01610 ops= "Cursor "; 01611 } else if (op==UNDO_INSERT_1) { 01612 ops= "Insert ascii "; 01613 } else if (op==UNDO_INSERT_2) { 01614 ops= "Insert 2 bytes "; 01615 } else if (op==UNDO_INSERT_3) { 01616 ops= "Insert 3 bytes "; 01617 } else if (op==UNDO_INSERT_4) { 01618 ops= "Insert unicode "; 01619 } else if (op==UNDO_BS_1) { 01620 ops= "Backspace for ascii "; 01621 } else if (op==UNDO_BS_2) { 01622 ops= "Backspace for 2 bytes "; 01623 } else if (op==UNDO_BS_3) { 01624 ops= "Backspace for 3 bytes "; 01625 } else if (op==UNDO_BS_4) { 01626 ops= "Backspace for unicode "; 01627 } else if (op==UNDO_DEL_1) { 01628 ops= "Delete ascii "; 01629 } else if (op==UNDO_DEL_2) { 01630 ops= "Delete 2 bytes "; 01631 } else if (op==UNDO_DEL_3) { 01632 ops= "Delete 3 bytes "; 01633 } else if (op==UNDO_DEL_4) { 01634 ops= "Delete unicode "; 01635 } else if (op==UNDO_SWAP) { 01636 ops= "Cursor swap"; 01637 } else if (op==UNDO_DBLOCK) { 01638 ops= "Delete text block"; 01639 } else if (op==UNDO_IBLOCK) { 01640 ops= "Insert text block"; 01641 } else if (op==UNDO_INDENT) { 01642 ops= "Indent "; 01643 } else if (op==UNDO_UNINDENT) { 01644 ops= "Unindent "; 01645 } else if (op==UNDO_COMMENT) { 01646 ops= "Comment "; 01647 } else if (op==UNDO_UNCOMMENT) { 01648 ops= "Uncomment "; 01649 } else { 01650 ops= "Unknown"; 01651 } 01652 01653 printf ("Op (%o) at %d = %s", op, i, ops); 01654 if (op >= UNDO_INSERT_1 && op <= UNDO_DEL_4) { 01655 i++; 01656 printf (" - Char is "); 01657 switch (op) { 01658 case UNDO_INSERT_1: case UNDO_BS_1: case UNDO_DEL_1: 01659 printf ("%c", text->undo_buf[i]); 01660 i++; 01661 break; 01662 case UNDO_INSERT_2: case UNDO_BS_2: case UNDO_DEL_2: 01663 printf ("%c%c", text->undo_buf[i], text->undo_buf[i+1]); 01664 i+=2; 01665 break; 01666 case UNDO_INSERT_3: case UNDO_BS_3: case UNDO_DEL_3: 01667 printf ("%c%c%c", text->undo_buf[i], text->undo_buf[i+1], text->undo_buf[i+2]); 01668 i+=3; 01669 break; 01670 case UNDO_INSERT_4: case UNDO_BS_4: case UNDO_DEL_4: { 01671 unsigned int uc; 01672 char c[BLI_UTF8_MAX+1]; 01673 size_t c_len; 01674 uc= text->undo_buf[i]; i++; 01675 uc= uc+(text->undo_buf[i]<<8); i++; 01676 uc= uc+(text->undo_buf[i]<<16); i++; 01677 uc= uc+(text->undo_buf[i]<<24); i++; 01678 c_len= BLI_str_utf8_from_unicode(uc, c); 01679 c[c_len]= '\0'; 01680 printf ("%s", c); 01681 } 01682 } 01683 } else if (op==UNDO_STO || op==UNDO_CTO) { 01684 i++; 01685 01686 charp= text->undo_buf[i]; i++; 01687 charp= charp+(text->undo_buf[i]<<8); i++; 01688 01689 linep= text->undo_buf[i]; i++; 01690 linep= linep+(text->undo_buf[i]<<8); i++; 01691 linep= linep+(text->undo_buf[i]<<16); i++; 01692 linep= linep+(text->undo_buf[i]<<24); i++; 01693 01694 printf ("to <%d, %d> ", linep, charp); 01695 01696 charp= text->undo_buf[i]; i++; 01697 charp= charp+(text->undo_buf[i]<<8); i++; 01698 01699 linep= text->undo_buf[i]; i++; 01700 linep= linep+(text->undo_buf[i]<<8); i++; 01701 linep= linep+(text->undo_buf[i]<<16); i++; 01702 linep= linep+(text->undo_buf[i]<<24); i++; 01703 01704 printf ("from <%d, %d>", linep, charp); 01705 } else if (op==UNDO_DBLOCK || op==UNDO_IBLOCK) { 01706 i++; 01707 01708 linep= text->undo_buf[i]; i++; 01709 linep= linep+(text->undo_buf[i]<<8); i++; 01710 linep= linep+(text->undo_buf[i]<<16); i++; 01711 linep= linep+(text->undo_buf[i]<<24); i++; 01712 01713 printf (" (length %d) <", linep); 01714 01715 while (linep>0) { 01716 putchar(text->undo_buf[i]); 01717 linep--; i++; 01718 } 01719 01720 linep= text->undo_buf[i]; i++; 01721 linep= linep+(text->undo_buf[i]<<8); i++; 01722 linep= linep+(text->undo_buf[i]<<16); i++; 01723 linep= linep+(text->undo_buf[i]<<24); i++; 01724 printf ("> (%d)", linep); 01725 } else if (op==UNDO_INDENT || op==UNDO_UNINDENT) { 01726 i++; 01727 01728 charp= text->undo_buf[i]; i++; 01729 charp= charp+(text->undo_buf[i]<<8); i++; 01730 01731 linep= text->undo_buf[i]; i++; 01732 linep= linep+(text->undo_buf[i]<<8); i++; 01733 linep= linep+(text->undo_buf[i]<<16); i++; 01734 linep= linep+(text->undo_buf[i]<<24); i++; 01735 01736 printf ("to <%d, %d> ", linep, charp); 01737 01738 charp= text->undo_buf[i]; i++; 01739 charp= charp+(text->undo_buf[i]<<8); i++; 01740 01741 linep= text->undo_buf[i]; i++; 01742 linep= linep+(text->undo_buf[i]<<8); i++; 01743 linep= linep+(text->undo_buf[i]<<16); i++; 01744 linep= linep+(text->undo_buf[i]<<24); i++; 01745 01746 printf ("from <%d, %d>", linep, charp); 01747 } 01748 01749 printf (" %d\n", i); 01750 i++; 01751 } 01752 } 01753 01754 static void txt_undo_add_op(Text *text, int op) 01755 { 01756 if(!max_undo_test(text, 2)) 01757 return; 01758 01759 text->undo_pos++; 01760 text->undo_buf[text->undo_pos]= op; 01761 text->undo_buf[text->undo_pos+1]= 0; 01762 } 01763 01764 static void txt_undo_store_uint16(char *undo_buf, int *undo_pos, unsigned short value) 01765 { 01766 undo_buf[*undo_pos]= (value)&0xff; 01767 (*undo_pos)++; 01768 undo_buf[*undo_pos]= (value>>8)&0xff; 01769 (*undo_pos)++; 01770 } 01771 01772 static void txt_undo_store_uint32(char *undo_buf, int *undo_pos, unsigned int value) 01773 { 01774 undo_buf[*undo_pos]= (value)&0xff; 01775 (*undo_pos)++; 01776 undo_buf[*undo_pos]= (value>>8)&0xff; 01777 (*undo_pos)++; 01778 undo_buf[*undo_pos]= (value>>16)&0xff; 01779 (*undo_pos)++; 01780 undo_buf[*undo_pos]= (value>>24)&0xff; 01781 (*undo_pos)++; 01782 } 01783 01784 static void txt_undo_add_block(Text *text, int op, const char *buf) 01785 { 01786 unsigned int length= strlen(buf); 01787 01788 if(!max_undo_test(text, length+11)) 01789 return; 01790 01791 text->undo_pos++; 01792 text->undo_buf[text->undo_pos]= op; 01793 text->undo_pos++; 01794 01795 txt_undo_store_uint32(text->undo_buf, &text->undo_pos, length); 01796 01797 strncpy(text->undo_buf+text->undo_pos, buf, length); 01798 text->undo_pos+=length; 01799 01800 txt_undo_store_uint32(text->undo_buf, &text->undo_pos, length); 01801 text->undo_buf[text->undo_pos]= op; 01802 01803 text->undo_buf[text->undo_pos+1]= 0; 01804 } 01805 01806 void txt_undo_add_toop(Text *text, int op, unsigned int froml, unsigned short fromc, unsigned int tol, unsigned short toc) 01807 { 01808 if(!max_undo_test(text, 15)) 01809 return; 01810 01811 if (froml==tol && fromc==toc) return; 01812 01813 text->undo_pos++; 01814 text->undo_buf[text->undo_pos]= op; 01815 01816 text->undo_pos++; 01817 01818 txt_undo_store_uint16(text->undo_buf, &text->undo_pos, fromc); 01819 txt_undo_store_uint32(text->undo_buf, &text->undo_pos, froml); 01820 txt_undo_store_uint16(text->undo_buf, &text->undo_pos, toc); 01821 txt_undo_store_uint32(text->undo_buf, &text->undo_pos, tol); 01822 01823 text->undo_buf[text->undo_pos]= op; 01824 01825 text->undo_buf[text->undo_pos+1]= 0; 01826 } 01827 01828 static void txt_undo_add_charop(Text *text, int op_start, unsigned int c) 01829 { 01830 char utf8[BLI_UTF8_MAX]; 01831 size_t i, utf8_size = BLI_str_utf8_from_unicode(c, utf8); 01832 01833 if(!max_undo_test(text, 3 + utf8_size)) 01834 return; 01835 01836 text->undo_pos++; 01837 01838 if (utf8_size < 4) { 01839 text->undo_buf[text->undo_pos]= op_start + utf8_size - 1; 01840 text->undo_pos++; 01841 01842 for (i = 0; i < utf8_size; i++) { 01843 text->undo_buf[text->undo_pos]= utf8[i]; 01844 text->undo_pos++; 01845 } 01846 01847 text->undo_buf[text->undo_pos]= op_start + utf8_size - 1; 01848 } else { 01849 text->undo_buf[text->undo_pos]= op_start + 3; 01850 text->undo_pos++; 01851 txt_undo_store_uint32(text->undo_buf, &text->undo_pos, c); 01852 text->undo_buf[text->undo_pos]= op_start + 3; 01853 } 01854 01855 text->undo_buf[text->undo_pos+1]= 0; 01856 } 01857 01858 static unsigned short txt_undo_read_uint16(const char *undo_buf, int *undo_pos) 01859 { 01860 unsigned short val; 01861 val= undo_buf[*undo_pos]; (*undo_pos)--; 01862 val= (val<<8)+undo_buf[*undo_pos]; (*undo_pos)--; 01863 return val; 01864 } 01865 01866 static unsigned int txt_undo_read_uint32(const char *undo_buf, int *undo_pos) 01867 { 01868 unsigned int val; 01869 val= undo_buf[*undo_pos]; (*undo_pos)--; 01870 val= (val<<8)+undo_buf[*undo_pos]; (*undo_pos)--; 01871 val= (val<<8)+undo_buf[*undo_pos]; (*undo_pos)--; 01872 val= (val<<8)+undo_buf[*undo_pos]; (*undo_pos)--; 01873 return val; 01874 } 01875 01876 static unsigned int txt_undo_read_unicode(const char *undo_buf, int *undo_pos, short bytes) 01877 { 01878 unsigned int unicode; 01879 char utf8[BLI_UTF8_MAX+1]; 01880 01881 switch (bytes) { 01882 case 1: /* ascii */ 01883 unicode = undo_buf[*undo_pos]; (*undo_pos)--; 01884 break; 01885 case 2: /* 2-byte symbol */ 01886 utf8[2] = '\0'; 01887 utf8[1] = undo_buf[*undo_pos]; (*undo_pos)--; 01888 utf8[0] = undo_buf[*undo_pos]; (*undo_pos)--; 01889 unicode= BLI_str_utf8_as_unicode(utf8); 01890 break; 01891 case 3: /* 3-byte symbol */ 01892 utf8[3] = '\0'; 01893 utf8[2] = undo_buf[*undo_pos]; (*undo_pos)--; 01894 utf8[1] = undo_buf[*undo_pos]; (*undo_pos)--; 01895 utf8[0] = undo_buf[*undo_pos]; (*undo_pos)--; 01896 unicode= BLI_str_utf8_as_unicode(utf8); 01897 break; 01898 case 4: /* 32-bit unicode symbol */ 01899 unicode= txt_undo_read_uint32(undo_buf, undo_pos); 01900 } 01901 01902 return unicode; 01903 } 01904 01905 static unsigned short txt_redo_read_uint16(const char *undo_buf, int *undo_pos) 01906 { 01907 unsigned short val; 01908 val = undo_buf[*undo_pos]; (*undo_pos)++; 01909 val = val+(undo_buf[*undo_pos]<<8); (*undo_pos)++; 01910 return val; 01911 } 01912 01913 static unsigned int txt_redo_read_uint32(const char *undo_buf, int *undo_pos) 01914 { 01915 unsigned int val; 01916 val= undo_buf[*undo_pos]; (*undo_pos)++; 01917 val= val+(undo_buf[*undo_pos]<<8); (*undo_pos)++; 01918 val= val+(undo_buf[*undo_pos]<<16); (*undo_pos)++; 01919 val= val+(undo_buf[*undo_pos]<<24); (*undo_pos)++; 01920 return val; 01921 } 01922 01923 static unsigned int txt_redo_read_unicode(const char *undo_buf, int *undo_pos, short bytes) 01924 { 01925 unsigned int unicode; 01926 char utf8[BLI_UTF8_MAX+1]; 01927 01928 switch (bytes) { 01929 case 1: /* ascii */ 01930 unicode = undo_buf[*undo_pos]; (*undo_pos)++; 01931 break; 01932 case 2: /* 2-byte symbol */ 01933 utf8[0] = undo_buf[*undo_pos]; (*undo_pos)++; 01934 utf8[1] = undo_buf[*undo_pos]; (*undo_pos)++; 01935 utf8[2] = '\0'; 01936 unicode= BLI_str_utf8_as_unicode(utf8); 01937 break; 01938 case 3: /* 3-byte symbol */ 01939 utf8[0] = undo_buf[*undo_pos]; (*undo_pos)++; 01940 utf8[1] = undo_buf[*undo_pos]; (*undo_pos)++; 01941 utf8[2] = undo_buf[*undo_pos]; (*undo_pos)++; 01942 utf8[3] = '\0'; 01943 unicode= BLI_str_utf8_as_unicode(utf8); 01944 break; 01945 case 4: /* 32-bit unicode symbol */ 01946 unicode= txt_undo_read_uint32(undo_buf, undo_pos); 01947 } 01948 01949 return unicode; 01950 } 01951 01952 void txt_do_undo(Text *text) 01953 { 01954 int op= text->undo_buf[text->undo_pos]; 01955 unsigned int linep, i; 01956 unsigned short charp; 01957 TextLine *holdl; 01958 int holdc, holdln; 01959 char *buf; 01960 01961 if (text->undo_pos<0) { 01962 return; 01963 } 01964 01965 text->undo_pos--; 01966 01967 undoing= 1; 01968 01969 switch(op) { 01970 case UNDO_CLEFT: 01971 txt_move_right(text, 0); 01972 break; 01973 01974 case UNDO_CRIGHT: 01975 txt_move_left(text, 0); 01976 break; 01977 01978 case UNDO_CUP: 01979 txt_move_down(text, 0); 01980 break; 01981 01982 case UNDO_CDOWN: 01983 txt_move_up(text, 0); 01984 break; 01985 01986 case UNDO_SLEFT: 01987 txt_move_right(text, 1); 01988 break; 01989 01990 case UNDO_SRIGHT: 01991 txt_move_left(text, 1); 01992 break; 01993 01994 case UNDO_SUP: 01995 txt_move_down(text, 1); 01996 break; 01997 01998 case UNDO_SDOWN: 01999 txt_move_up(text, 1); 02000 break; 02001 02002 case UNDO_CTO: 02003 case UNDO_STO: 02004 text->undo_pos--; 02005 text->undo_pos--; 02006 text->undo_pos--; 02007 text->undo_pos--; 02008 02009 text->undo_pos--; 02010 text->undo_pos--; 02011 02012 linep= txt_undo_read_uint32(text->undo_buf, &text->undo_pos); 02013 charp= txt_undo_read_uint16(text->undo_buf, &text->undo_pos); 02014 02015 if (op==UNDO_CTO) { 02016 txt_move_toline(text, linep, 0); 02017 text->curc= charp; 02018 txt_pop_sel(text); 02019 } else { 02020 txt_move_toline(text, linep, 1); 02021 text->selc= charp; 02022 } 02023 02024 text->undo_pos--; 02025 break; 02026 02027 case UNDO_INSERT_1: case UNDO_INSERT_2: case UNDO_INSERT_3: case UNDO_INSERT_4: 02028 txt_backspace_char(text); 02029 text->undo_pos-= op - UNDO_INSERT_1 + 1; 02030 text->undo_pos--; 02031 break; 02032 02033 case UNDO_BS_1: case UNDO_BS_2: case UNDO_BS_3: case UNDO_BS_4: 02034 charp = op - UNDO_BS_1 + 1; 02035 txt_add_char(text, txt_undo_read_unicode(text->undo_buf, &text->undo_pos, charp)); 02036 text->undo_pos--; 02037 break; 02038 02039 case UNDO_DEL_1: case UNDO_DEL_2: case UNDO_DEL_3: case UNDO_DEL_4: 02040 charp = op - UNDO_DEL_1 + 1; 02041 txt_add_char(text, txt_undo_read_unicode(text->undo_buf, &text->undo_pos, charp)); 02042 txt_move_left(text, 0); 02043 text->undo_pos--; 02044 break; 02045 02046 case UNDO_SWAP: 02047 txt_curs_swap(text); 02048 break; 02049 02050 case UNDO_DBLOCK: 02051 linep= txt_undo_read_uint32(text->undo_buf, &text->undo_pos); 02052 02053 buf= MEM_mallocN(linep+1, "dblock buffer"); 02054 for (i=0; i < linep; i++){ 02055 buf[(linep-1)-i]= text->undo_buf[text->undo_pos]; 02056 text->undo_pos--; 02057 } 02058 buf[i]= 0; 02059 02060 txt_curs_first(text, &holdl, &holdc); 02061 holdln= txt_get_span(text->lines.first, holdl); 02062 02063 txt_insert_buf(text, buf); 02064 MEM_freeN(buf); 02065 02066 text->curl= text->lines.first; 02067 while (holdln>0) { 02068 if(text->curl->next) 02069 text->curl= text->curl->next; 02070 02071 holdln--; 02072 } 02073 text->curc= holdc; 02074 02075 text->undo_pos--; 02076 text->undo_pos--; 02077 text->undo_pos--; 02078 text->undo_pos--; 02079 02080 text->undo_pos--; 02081 02082 break; 02083 02084 case UNDO_IBLOCK: 02085 linep= txt_undo_read_uint32(text->undo_buf, &text->undo_pos); 02086 txt_delete_sel(text); 02087 02088 /* txt_backspace_char removes utf8-characters, not bytes */ 02089 buf= MEM_mallocN(linep+1, "iblock buffer"); 02090 for (i=0; i < linep; i++){ 02091 buf[(linep-1)-i]= text->undo_buf[text->undo_pos]; 02092 text->undo_pos--; 02093 } 02094 buf[i]= 0; 02095 linep= txt_utf8_len(buf); 02096 MEM_freeN(buf); 02097 02098 while (linep>0) { 02099 txt_backspace_char(text); 02100 linep--; 02101 } 02102 02103 text->undo_pos--; 02104 text->undo_pos--; 02105 text->undo_pos--; 02106 text->undo_pos--; 02107 02108 text->undo_pos--; 02109 02110 break; 02111 case UNDO_INDENT: 02112 case UNDO_UNINDENT: 02113 case UNDO_COMMENT: 02114 case UNDO_UNCOMMENT: 02115 linep= txt_undo_read_uint32(text->undo_buf, &text->undo_pos); 02116 //linep is now the end line of the selection 02117 02118 charp = txt_undo_read_uint16(text->undo_buf, &text->undo_pos); 02119 //charp is the last char selected or text->line->len 02120 02121 //set the selection for this now 02122 text->selc = charp; 02123 text->sell = text->lines.first; 02124 for (i= 0; i < linep; i++) { 02125 text->sell = text->sell->next; 02126 } 02127 02128 linep= txt_undo_read_uint32(text->undo_buf, &text->undo_pos); 02129 //first line to be selected 02130 02131 charp = txt_undo_read_uint16(text->undo_buf, &text->undo_pos); 02132 //first postion to be selected 02133 text->curc = charp; 02134 text->curl = text->lines.first; 02135 for (i = 0; i < linep; i++) { 02136 text->curl = text->curl->next; 02137 } 02138 02139 02140 if (op==UNDO_INDENT) { 02141 txt_unindent(text); 02142 } else if (op== UNDO_UNINDENT) { 02143 txt_indent(text); 02144 } else if (op == UNDO_COMMENT) { 02145 txt_uncomment(text); 02146 } else if (op == UNDO_UNCOMMENT) { 02147 txt_comment(text); 02148 } 02149 02150 text->undo_pos--; 02151 break; 02152 default: 02153 //XXX error("Undo buffer error - resetting"); 02154 text->undo_pos= -1; 02155 02156 break; 02157 } 02158 02159 /* next undo step may need evaluating */ 02160 if (text->undo_pos>=0) { 02161 switch (text->undo_buf[text->undo_pos]) { 02162 case UNDO_STO: 02163 txt_do_undo(text); 02164 txt_do_redo(text); /* selections need restoring */ 02165 break; 02166 case UNDO_SWAP: 02167 txt_do_undo(text); /* swaps should appear transparent */ 02168 break; 02169 } 02170 } 02171 02172 undoing= 0; 02173 } 02174 02175 void txt_do_redo(Text *text) 02176 { 02177 char op; 02178 unsigned int linep, i; 02179 unsigned short charp; 02180 char *buf; 02181 02182 text->undo_pos++; 02183 op= text->undo_buf[text->undo_pos]; 02184 02185 if (!op) { 02186 text->undo_pos--; 02187 return; 02188 } 02189 02190 undoing= 1; 02191 02192 switch(op) { 02193 case UNDO_CLEFT: 02194 txt_move_left(text, 0); 02195 break; 02196 02197 case UNDO_CRIGHT: 02198 txt_move_right(text, 0); 02199 break; 02200 02201 case UNDO_CUP: 02202 txt_move_up(text, 0); 02203 break; 02204 02205 case UNDO_CDOWN: 02206 txt_move_down(text, 0); 02207 break; 02208 02209 case UNDO_SLEFT: 02210 txt_move_left(text, 1); 02211 break; 02212 02213 case UNDO_SRIGHT: 02214 txt_move_right(text, 1); 02215 break; 02216 02217 case UNDO_SUP: 02218 txt_move_up(text, 1); 02219 break; 02220 02221 case UNDO_SDOWN: 02222 txt_move_down(text, 1); 02223 break; 02224 02225 case UNDO_INSERT_1: case UNDO_INSERT_2: case UNDO_INSERT_3: case UNDO_INSERT_4: 02226 text->undo_pos++; 02227 charp = op - UNDO_INSERT_1 + 1; 02228 txt_add_char(text, txt_redo_read_unicode(text->undo_buf, &text->undo_pos, charp)); 02229 break; 02230 02231 case UNDO_BS_1: case UNDO_BS_2: case UNDO_BS_3: case UNDO_BS_4: 02232 text->undo_pos++; 02233 txt_backspace_char(text); 02234 text->undo_pos+= op - UNDO_BS_1 + 1; 02235 break; 02236 02237 case UNDO_DEL_1: case UNDO_DEL_2: case UNDO_DEL_3: case UNDO_DEL_4: 02238 text->undo_pos++; 02239 txt_delete_char(text); 02240 text->undo_pos+= op - UNDO_DEL_1 + 1; 02241 break; 02242 02243 case UNDO_SWAP: 02244 txt_curs_swap(text); 02245 txt_do_redo(text); /* swaps should appear transparent a*/ 02246 break; 02247 02248 case UNDO_CTO: 02249 case UNDO_STO: 02250 text->undo_pos++; 02251 text->undo_pos++; 02252 02253 text->undo_pos++; 02254 text->undo_pos++; 02255 text->undo_pos++; 02256 text->undo_pos++; 02257 02258 text->undo_pos++; 02259 02260 charp= txt_redo_read_uint16(text->undo_buf, &text->undo_pos); 02261 linep= txt_redo_read_uint32(text->undo_buf, &text->undo_pos); 02262 02263 if (op==UNDO_CTO) { 02264 txt_move_toline(text, linep, 0); 02265 text->curc= charp; 02266 txt_pop_sel(text); 02267 } else { 02268 txt_move_toline(text, linep, 1); 02269 text->selc= charp; 02270 } 02271 02272 break; 02273 02274 case UNDO_DBLOCK: 02275 text->undo_pos++; 02276 linep= txt_redo_read_uint32(text->undo_buf, &text->undo_pos); 02277 txt_delete_sel(text); 02278 02279 text->undo_pos+=linep; 02280 02281 text->undo_pos++; 02282 text->undo_pos++; 02283 text->undo_pos++; 02284 text->undo_pos++; 02285 02286 break; 02287 02288 case UNDO_IBLOCK: 02289 text->undo_pos++; 02290 linep= txt_redo_read_uint32(text->undo_buf, &text->undo_pos); 02291 02292 buf= MEM_mallocN(linep+1, "iblock buffer"); 02293 memcpy (buf, &text->undo_buf[text->undo_pos], linep); 02294 text->undo_pos+= linep; 02295 buf[linep]= 0; 02296 02297 txt_insert_buf(text, buf); 02298 MEM_freeN(buf); 02299 02300 text->undo_pos++; 02301 text->undo_pos++; 02302 text->undo_pos++; 02303 text->undo_pos++; 02304 break; 02305 02306 case UNDO_INDENT: 02307 case UNDO_UNINDENT: 02308 case UNDO_COMMENT: 02309 case UNDO_UNCOMMENT: 02310 text->undo_pos++; 02311 charp = txt_redo_read_uint16(text->undo_buf, &text->undo_pos); 02312 //charp is the first char selected or 0 02313 02314 linep= txt_redo_read_uint32(text->undo_buf, &text->undo_pos); 02315 //linep is now the first line of the selection 02316 //set the selcetion for this now 02317 text->curc = charp; 02318 text->curl = text->lines.first; 02319 for (i= 0; i < linep; i++) { 02320 text->curl = text->curl->next; 02321 } 02322 02323 charp = txt_redo_read_uint16(text->undo_buf, &text->undo_pos); 02324 //last postion to be selected 02325 02326 linep= txt_redo_read_uint32(text->undo_buf, &text->undo_pos); 02327 //Last line to be selected 02328 02329 text->selc = charp; 02330 text->sell = text->lines.first; 02331 for (i = 0; i < linep; i++) { 02332 text->sell = text->sell->next; 02333 } 02334 02335 if (op==UNDO_INDENT) { 02336 txt_indent(text); 02337 } else if (op== UNDO_UNINDENT) { 02338 txt_unindent(text); 02339 } else if (op == UNDO_COMMENT) { 02340 txt_comment(text); 02341 } else if (op == UNDO_UNCOMMENT) { 02342 txt_uncomment(text); 02343 } 02344 break; 02345 default: 02346 //XXX error("Undo buffer error - resetting"); 02347 text->undo_pos= -1; 02348 02349 break; 02350 } 02351 02352 undoing= 0; 02353 } 02354 02355 /**************************/ 02356 /* Line editing functions */ 02357 /**************************/ 02358 02359 void txt_split_curline (Text *text) 02360 { 02361 TextLine *ins; 02362 TextMarker *mrk; 02363 char *left, *right; 02364 int lineno= -1; 02365 02366 if (!text) return; 02367 if (!text->curl) return; 02368 02369 txt_delete_sel(text); 02370 02371 /* Move markers */ 02372 02373 lineno= txt_get_span(text->lines.first, text->curl); 02374 mrk= text->markers.first; 02375 while (mrk) { 02376 if (mrk->lineno==lineno && mrk->start>text->curc) { 02377 mrk->lineno++; 02378 mrk->start -= text->curc; 02379 mrk->end -= text->curc; 02380 } else if (mrk->lineno > lineno) { 02381 mrk->lineno++; 02382 } 02383 mrk= mrk->next; 02384 } 02385 02386 /* Make the two half strings */ 02387 02388 left= MEM_mallocN(text->curc+1, "textline_string"); 02389 if (text->curc) memcpy(left, text->curl->line, text->curc); 02390 left[text->curc]=0; 02391 02392 right= MEM_mallocN(text->curl->len - text->curc+1, "textline_string"); 02393 memcpy(right, text->curl->line+text->curc, text->curl->len-text->curc+1); 02394 02395 MEM_freeN(text->curl->line); 02396 if (text->curl->format) MEM_freeN(text->curl->format); 02397 02398 /* Make the new TextLine */ 02399 02400 ins= MEM_mallocN(sizeof(TextLine), "textline"); 02401 ins->line= left; 02402 ins->format= NULL; 02403 ins->len= text->curc; 02404 02405 text->curl->line= right; 02406 text->curl->format= NULL; 02407 text->curl->len= text->curl->len - text->curc; 02408 02409 BLI_insertlinkbefore(&text->lines, text->curl, ins); 02410 02411 text->curc=0; 02412 02413 txt_make_dirty(text); 02414 txt_clean_text(text); 02415 02416 txt_pop_sel(text); 02417 if(!undoing) txt_undo_add_charop(text, UNDO_INSERT_1, '\n'); 02418 } 02419 02420 static void txt_delete_line (Text *text, TextLine *line) 02421 { 02422 TextMarker *mrk=NULL, *nxt; 02423 int lineno= -1; 02424 02425 if (!text) return; 02426 if (!text->curl) return; 02427 02428 lineno= txt_get_span(text->lines.first, line); 02429 mrk= text->markers.first; 02430 while (mrk) { 02431 nxt= mrk->next; 02432 if (mrk->lineno==lineno) 02433 BLI_freelinkN(&text->markers, mrk); 02434 else if (mrk->lineno > lineno) 02435 mrk->lineno--; 02436 mrk= nxt; 02437 } 02438 02439 BLI_remlink (&text->lines, line); 02440 02441 if (line->line) MEM_freeN(line->line); 02442 if (line->format) MEM_freeN(line->format); 02443 02444 MEM_freeN(line); 02445 02446 txt_make_dirty(text); 02447 txt_clean_text(text); 02448 } 02449 02450 static void txt_combine_lines (Text *text, TextLine *linea, TextLine *lineb) 02451 { 02452 char *tmp; 02453 TextMarker *mrk= NULL; 02454 int lineno=-1; 02455 02456 if (!text) return; 02457 02458 if(!linea || !lineb) return; 02459 02460 mrk= txt_find_marker_region(text, lineb, 0, lineb->len, 0, 0); 02461 if (mrk) { 02462 lineno= mrk->lineno; 02463 do { 02464 mrk->lineno--; 02465 mrk->start += linea->len; 02466 mrk->end += linea->len; 02467 mrk= mrk->next; 02468 } while (mrk && mrk->lineno==lineno); 02469 } 02470 if (lineno==-1) lineno= txt_get_span(text->lines.first, lineb); 02471 02472 tmp= MEM_mallocN(linea->len+lineb->len+1, "textline_string"); 02473 02474 strcpy(tmp, linea->line); 02475 strcat(tmp, lineb->line); 02476 02477 make_new_line(linea, tmp); 02478 02479 txt_delete_line(text, lineb); 02480 02481 txt_make_dirty(text); 02482 txt_clean_text(text); 02483 } 02484 02485 void txt_delete_char(Text *text) 02486 { 02487 unsigned int c='\n'; 02488 02489 if (!text) return; 02490 if (!text->curl) return; 02491 02492 if (txt_has_sel(text)) { /* deleting a selection */ 02493 txt_delete_sel(text); 02494 txt_make_dirty(text); 02495 return; 02496 } 02497 else if (text->curc== text->curl->len) { /* Appending two lines */ 02498 if (text->curl->next) { 02499 txt_combine_lines(text, text->curl, text->curl->next); 02500 txt_pop_sel(text); 02501 } 02502 } else { /* Just deleting a char */ 02503 size_t c_len = 0; 02504 TextMarker *mrk; 02505 c= BLI_str_utf8_as_unicode_and_size(text->curl->line + text->curc, &c_len); 02506 02507 mrk= txt_find_marker_region(text, text->curl, text->curc - c_len, text->curl->len, 0, 0); 02508 if (mrk) { 02509 int lineno= mrk->lineno; 02510 if (mrk->end==text->curc) { 02511 if ((mrk->flags & TMARK_TEMP) && !(mrk->flags & TMARK_EDITALL)) { 02512 txt_clear_markers(text, mrk->group, TMARK_TEMP); 02513 } else { 02514 BLI_freelinkN(&text->markers, mrk); 02515 } 02516 return; 02517 } 02518 do { 02519 if (mrk->start>text->curc) mrk->start-= c_len; 02520 mrk->end-= c_len; 02521 mrk= mrk->next; 02522 } while (mrk && mrk->lineno==lineno); 02523 } 02524 02525 memmove(text->curl->line+text->curc, text->curl->line+text->curc+c_len, text->curl->len-text->curc-c_len+1); 02526 02527 text->curl->len-= c_len; 02528 02529 txt_pop_sel(text); 02530 } 02531 02532 txt_make_dirty(text); 02533 txt_clean_text(text); 02534 02535 if(!undoing) txt_undo_add_charop(text, UNDO_DEL_1, c); 02536 } 02537 02538 void txt_delete_word (Text *text) 02539 { 02540 txt_jump_right(text, 1); 02541 txt_delete_sel(text); 02542 } 02543 02544 void txt_backspace_char (Text *text) 02545 { 02546 unsigned int c='\n'; 02547 02548 if (!text) return; 02549 if (!text->curl) return; 02550 02551 if (txt_has_sel(text)) { /* deleting a selection */ 02552 txt_delete_sel(text); 02553 txt_make_dirty(text); 02554 return; 02555 } 02556 else if (text->curc==0) { /* Appending two lines */ 02557 if (!text->curl->prev) return; 02558 02559 text->curl= text->curl->prev; 02560 text->curc= text->curl->len; 02561 02562 txt_combine_lines(text, text->curl, text->curl->next); 02563 txt_pop_sel(text); 02564 } 02565 else { /* Just backspacing a char */ 02566 size_t c_len = 0; 02567 TextMarker *mrk; 02568 char *prev = BLI_str_prev_char_utf8(text->curl->line + text->curc); 02569 c= BLI_str_utf8_as_unicode_and_size(prev, &c_len); 02570 02571 mrk= txt_find_marker_region(text, text->curl, text->curc - c_len, text->curl->len, 0, 0); 02572 if (mrk) { 02573 int lineno= mrk->lineno; 02574 if (mrk->start==text->curc) { 02575 if ((mrk->flags & TMARK_TEMP) && !(mrk->flags & TMARK_EDITALL)) { 02576 txt_clear_markers(text, mrk->group, TMARK_TEMP); 02577 } else { 02578 BLI_freelinkN(&text->markers, mrk); 02579 } 02580 return; 02581 } 02582 do { 02583 if (mrk->start>text->curc - c_len) mrk->start-= c_len; 02584 mrk->end-= c_len; 02585 mrk= mrk->next; 02586 } while (mrk && mrk->lineno==lineno); 02587 } 02588 02589 memcpy(text->curl->line + text->curc - c_len, text->curl->line + text->curc, text->curl->len-text->curc+1); 02590 02591 text->curl->len-= c_len; 02592 text->curc-= c_len; 02593 02594 txt_pop_sel(text); 02595 } 02596 02597 txt_make_dirty(text); 02598 txt_clean_text(text); 02599 02600 if(!undoing) txt_undo_add_charop(text, UNDO_BS_1, c); 02601 } 02602 02603 void txt_backspace_word (Text *text) 02604 { 02605 txt_jump_left(text, 1); 02606 txt_delete_sel(text); 02607 } 02608 02609 /* Max spaces to replace a tab with, currently hardcoded to TXT_TABSIZE = 4. 02610 * Used by txt_convert_tab_to_spaces, indent and unintent. 02611 * Remember to change this string according to max tab size */ 02612 static char tab_to_spaces[] = " "; 02613 02614 static void txt_convert_tab_to_spaces (Text *text) 02615 { 02616 /* sb aims to pad adjust the tab-width needed so that the right number of spaces 02617 * is added so that the indention of the line is the right width (i.e. aligned 02618 * to multiples of TXT_TABSIZE) 02619 */ 02620 char *sb = &tab_to_spaces[text->curc % TXT_TABSIZE]; 02621 txt_insert_buf(text, sb); 02622 } 02623 02624 static int txt_add_char_intern (Text *text, unsigned int add, int replace_tabs) 02625 { 02626 int lineno; 02627 char *tmp, ch[BLI_UTF8_MAX]; 02628 TextMarker *mrk; 02629 size_t add_len; 02630 02631 if (!text) return 0; 02632 if (!text->curl) return 0; 02633 02634 if (add=='\n') { 02635 txt_split_curline(text); 02636 return 1; 02637 } 02638 02639 /* insert spaces rather than tabs */ 02640 if (add == '\t' && replace_tabs) { 02641 txt_convert_tab_to_spaces(text); 02642 return 1; 02643 } 02644 02645 txt_delete_sel(text); 02646 02647 add_len = BLI_str_utf8_from_unicode(add, ch); 02648 mrk= txt_find_marker_region(text, text->curl, text->curc-1, text->curl->len, 0, 0); 02649 if (mrk) { 02650 lineno= mrk->lineno; 02651 do { 02652 if (mrk->start>text->curc) mrk->start+= add_len; 02653 mrk->end+= add_len; 02654 mrk= mrk->next; 02655 } while (mrk && mrk->lineno==lineno); 02656 } 02657 02658 tmp= MEM_mallocN(text->curl->len+add_len+1, "textline_string"); 02659 02660 memcpy(tmp, text->curl->line, text->curc); 02661 memcpy(tmp+text->curc, ch, add_len); 02662 memcpy(tmp+text->curc+add_len, text->curl->line+text->curc, text->curl->len-text->curc+1); 02663 02664 make_new_line(text->curl, tmp); 02665 02666 text->curc+= add_len; 02667 02668 txt_pop_sel(text); 02669 02670 txt_make_dirty(text); 02671 txt_clean_text(text); 02672 02673 if(!undoing) txt_undo_add_charop(text, UNDO_INSERT_1, add); 02674 return 1; 02675 } 02676 02677 int txt_add_char (Text *text, unsigned int add) 02678 { 02679 return txt_add_char_intern(text, add, text->flags & TXT_TABSTOSPACES); 02680 } 02681 02682 int txt_add_raw_char (Text *text, unsigned int add) 02683 { 02684 return txt_add_char_intern(text, add, 0); 02685 } 02686 02687 void txt_delete_selected(Text *text) 02688 { 02689 txt_delete_sel(text); 02690 txt_make_dirty(text); 02691 } 02692 02693 int txt_replace_char (Text *text, unsigned int add) 02694 { 02695 unsigned int del; 02696 size_t del_size = 0, add_size; 02697 char ch[BLI_UTF8_MAX]; 02698 02699 if (!text) return 0; 02700 if (!text->curl) return 0; 02701 02702 /* If text is selected or we're at the end of the line just use txt_add_char */ 02703 if (text->curc==text->curl->len || txt_has_sel(text) || add=='\n') { 02704 int i= txt_add_char(text, add); 02705 TextMarker *mrk= txt_find_marker(text, text->curl, text->curc, 0, 0); 02706 if (mrk) BLI_freelinkN(&text->markers, mrk); 02707 return i; 02708 } 02709 02710 del= BLI_str_utf8_as_unicode_and_size(text->curl->line + text->curc, &del_size); 02711 add_size= BLI_str_utf8_from_unicode(add, ch); 02712 02713 if (add_size > del_size) { 02714 char *tmp= MEM_mallocN(text->curl->len+add_size-del_size+1, "textline_string"); 02715 memcpy(tmp, text->curl->line, text->curc); 02716 memcpy(tmp+text->curc+add_size, text->curl->line+text->curc+del_size, text->curl->len-text->curc-del_size+1); 02717 MEM_freeN(text->curl->line); 02718 text->curl->line = tmp; 02719 } else if (add_size < del_size) { 02720 char *tmp= text->curl->line; 02721 memmove(tmp+text->curc+add_size, tmp+text->curc+del_size, text->curl->len-text->curc-del_size+1); 02722 } 02723 02724 memcpy(text->curl->line + text->curc, ch, add_size); 02725 text->curc+= add_size; 02726 02727 txt_pop_sel(text); 02728 txt_make_dirty(text); 02729 txt_clean_text(text); 02730 02731 /* Should probably create a new op for this */ 02732 if(!undoing) { 02733 txt_undo_add_charop(text, UNDO_DEL_1, del); 02734 txt_undo_add_charop(text, UNDO_INSERT_1, add); 02735 } 02736 return 1; 02737 } 02738 02739 void txt_indent(Text *text) 02740 { 02741 int len, num; 02742 char *tmp; 02743 02744 const char *add = "\t"; 02745 int indentlen = 1; 02746 02747 /* hardcoded: TXT_TABSIZE = 4 spaces: */ 02748 int spaceslen = TXT_TABSIZE; 02749 02750 /* insert spaces rather than tabs */ 02751 if (text->flags & TXT_TABSTOSPACES){ 02752 add = tab_to_spaces; 02753 indentlen = spaceslen; 02754 } 02755 02756 if (!text) return; 02757 if (!text->curl) return; 02758 if (!text->sell) return; 02759 02760 num = 0; 02761 while (TRUE) 02762 { 02763 tmp= MEM_mallocN(text->curl->len+indentlen+1, "textline_string"); 02764 02765 text->curc = 0; 02766 if(text->curc) memcpy(tmp, text->curl->line, text->curc); /* XXX never true, check prev line */ 02767 memcpy(tmp+text->curc, add, indentlen); 02768 02769 len= text->curl->len - text->curc; 02770 if(len>0) memcpy(tmp+text->curc+indentlen, text->curl->line+text->curc, len); 02771 tmp[text->curl->len+indentlen]= 0; 02772 02773 make_new_line(text->curl, tmp); 02774 02775 text->curc+= indentlen; 02776 02777 txt_make_dirty(text); 02778 txt_clean_text(text); 02779 02780 if(text->curl == text->sell) 02781 { 02782 text->selc = text->sell->len; 02783 break; 02784 } else { 02785 text->curl = text->curl->next; 02786 num++; 02787 } 02788 } 02789 text->curc = 0; 02790 while( num > 0 ) 02791 { 02792 text->curl = text->curl->prev; 02793 num--; 02794 } 02795 02796 if(!undoing) 02797 { 02798 txt_undo_add_toop(text, UNDO_INDENT, txt_get_span(text->lines.first, text->curl), text->curc, txt_get_span(text->lines.first, text->sell), text->selc); 02799 } 02800 } 02801 02802 void txt_unindent(Text *text) 02803 { 02804 int num = 0; 02805 const char *remove = "\t"; 02806 int indent = 1; 02807 02808 /* hardcoded: TXT_TABSIZE = 4 spaces: */ 02809 int spaceslen = TXT_TABSIZE; 02810 02811 /* insert spaces rather than tabs */ 02812 if (text->flags & TXT_TABSTOSPACES){ 02813 remove = tab_to_spaces; 02814 indent = spaceslen; 02815 } 02816 02817 if (!text) return; 02818 if (!text->curl) return; 02819 if (!text->sell) return; 02820 02821 while(TRUE) 02822 { 02823 int i = 0; 02824 02825 if (BLI_strncasecmp(text->curl->line, remove, indent) == 0) 02826 { 02827 while(i< text->curl->len) { 02828 text->curl->line[i]= text->curl->line[i+indent]; 02829 i++; 02830 } 02831 text->curl->len-= indent; 02832 } 02833 02834 txt_make_dirty(text); 02835 txt_clean_text(text); 02836 02837 if(text->curl == text->sell) 02838 { 02839 text->selc = text->sell->len; 02840 break; 02841 } else { 02842 text->curl = text->curl->next; 02843 num++; 02844 } 02845 02846 } 02847 text->curc = 0; 02848 while( num > 0 ) 02849 { 02850 text->curl = text->curl->prev; 02851 num--; 02852 } 02853 02854 if(!undoing) 02855 { 02856 txt_undo_add_toop(text, UNDO_UNINDENT, txt_get_span(text->lines.first, text->curl), text->curc, txt_get_span(text->lines.first, text->sell), text->selc); 02857 } 02858 } 02859 02860 void txt_comment(Text *text) 02861 { 02862 int len, num; 02863 char *tmp; 02864 char add = '#'; 02865 02866 if (!text) return; 02867 if (!text->curl) return; 02868 if (!text->sell) return;// Need to change this need to check if only one line is selected to more then one 02869 02870 num = 0; 02871 while (TRUE) 02872 { 02873 tmp= MEM_mallocN(text->curl->len+2, "textline_string"); 02874 02875 text->curc = 0; 02876 if(text->curc) memcpy(tmp, text->curl->line, text->curc); 02877 tmp[text->curc]= add; 02878 02879 len= text->curl->len - text->curc; 02880 if(len>0) memcpy(tmp+text->curc+1, text->curl->line+text->curc, len); 02881 tmp[text->curl->len+1]=0; 02882 02883 make_new_line(text->curl, tmp); 02884 02885 text->curc++; 02886 02887 txt_make_dirty(text); 02888 txt_clean_text(text); 02889 02890 if(text->curl == text->sell) 02891 { 02892 text->selc = text->sell->len; 02893 break; 02894 } else { 02895 text->curl = text->curl->next; 02896 num++; 02897 } 02898 } 02899 text->curc = 0; 02900 while( num > 0 ) 02901 { 02902 text->curl = text->curl->prev; 02903 num--; 02904 } 02905 02906 if(!undoing) 02907 { 02908 txt_undo_add_toop(text, UNDO_COMMENT, txt_get_span(text->lines.first, text->curl), text->curc, txt_get_span(text->lines.first, text->sell), text->selc); 02909 } 02910 } 02911 02912 void txt_uncomment(Text *text) 02913 { 02914 int num = 0; 02915 char remove = '#'; 02916 02917 if (!text) return; 02918 if (!text->curl) return; 02919 if (!text->sell) return; 02920 02921 while(TRUE) 02922 { 02923 int i = 0; 02924 02925 if (text->curl->line[i] == remove) 02926 { 02927 while(i< text->curl->len) { 02928 text->curl->line[i]= text->curl->line[i+1]; 02929 i++; 02930 } 02931 text->curl->len--; 02932 } 02933 02934 02935 txt_make_dirty(text); 02936 txt_clean_text(text); 02937 02938 if(text->curl == text->sell) 02939 { 02940 text->selc = text->sell->len; 02941 break; 02942 } else { 02943 text->curl = text->curl->next; 02944 num++; 02945 } 02946 02947 } 02948 text->curc = 0; 02949 while( num > 0 ) 02950 { 02951 text->curl = text->curl->prev; 02952 num--; 02953 } 02954 02955 if(!undoing) 02956 { 02957 txt_undo_add_toop(text, UNDO_UNCOMMENT, txt_get_span(text->lines.first, text->curl), text->curc, txt_get_span(text->lines.first, text->sell), text->selc); 02958 } 02959 } 02960 02961 int setcurr_tab_spaces (Text *text, int space) 02962 { 02963 int i = 0; 02964 int test = 0; 02965 const char *word = ":"; 02966 const char *comm = "#"; 02967 const char indent= (text->flags & TXT_TABSTOSPACES) ? ' ' : '\t'; 02968 static const char *back_words[]= {"return", "break", "continue", "pass", "yield", NULL}; 02969 if (!text) return 0; 02970 if (!text->curl) return 0; 02971 02972 while (text->curl->line[i] == indent) 02973 { 02974 //we only count those tabs/spaces that are before any text or before the curs; 02975 if (i == text->curc) 02976 { 02977 return i; 02978 } else { 02979 i++; 02980 } 02981 } 02982 if(strstr(text->curl->line, word)) 02983 { 02984 /* if we find a ':' on this line, then add a tab but not if it is: 02985 * 1) in a comment 02986 * 2) within an identifier 02987 * 3) after the cursor (text->curc), i.e. when creating space before a function def [#25414] 02988 */ 02989 int a, is_indent = 0; 02990 for(a=0; (a < text->curc) && (text->curl->line[a] != '\0'); a++) 02991 { 02992 char ch= text->curl->line[a]; 02993 if (ch=='#') { 02994 break; 02995 } else if (ch==':') { 02996 is_indent = 1; 02997 } else if (ch!=' ' && ch!='\t') { 02998 is_indent = 0; 02999 } 03000 } 03001 if (is_indent) { 03002 i += space; 03003 } 03004 } 03005 03006 for(test=0; back_words[test]; test++) 03007 { 03008 /* if there are these key words then remove a tab because we are done with the block */ 03009 if(strstr(text->curl->line, back_words[test]) && i > 0) 03010 { 03011 if(strcspn(text->curl->line, back_words[test]) < strcspn(text->curl->line, comm)) 03012 { 03013 i -= space; 03014 } 03015 } 03016 } 03017 return i; 03018 } 03019 03020 /*********************************/ 03021 /* Text marker utility functions */ 03022 /*********************************/ 03023 03024 /* Creates and adds a marker to the list maintaining sorted order */ 03025 void txt_add_marker(Text *text, TextLine *line, int start, int end, const unsigned char color[4], int group, int flags) 03026 { 03027 TextMarker *tmp, *marker; 03028 03029 marker= MEM_mallocN(sizeof(TextMarker), "text_marker"); 03030 03031 marker->lineno= txt_get_span(text->lines.first, line); 03032 marker->start= MIN2(start, end); 03033 marker->end= MAX2(start, end); 03034 marker->group= group; 03035 marker->flags= flags; 03036 03037 marker->color[0]= color[0]; 03038 marker->color[1]= color[1]; 03039 marker->color[2]= color[2]; 03040 marker->color[3]= color[3]; 03041 03042 for (tmp=text->markers.last; tmp; tmp=tmp->prev) 03043 if (tmp->lineno < marker->lineno || (tmp->lineno==marker->lineno && tmp->start < marker->start)) 03044 break; 03045 03046 if (tmp) BLI_insertlinkafter(&text->markers, tmp, marker); 03047 else BLI_addhead(&text->markers, marker); 03048 } 03049 03050 /* Returns the first matching marker on the specified line between two points. 03051 If the group or flags fields are non-zero the returned flag must be in the 03052 specified group and have at least the specified flags set. */ 03053 TextMarker *txt_find_marker_region(Text *text, TextLine *line, int start, int end, int group, int flags) 03054 { 03055 TextMarker *marker, *next; 03056 int lineno= txt_get_span(text->lines.first, line); 03057 03058 for (marker=text->markers.first; marker; marker=next) { 03059 next= marker->next; 03060 03061 if (group && marker->group != group) continue; 03062 else if ((marker->flags & flags) != flags) continue; 03063 else if (marker->lineno < lineno) continue; 03064 else if (marker->lineno > lineno) break; 03065 03066 if ((marker->start==marker->end && start<=marker->start && marker->start<=end) || 03067 (marker->start<end && marker->end>start)) 03068 return marker; 03069 } 03070 return NULL; 03071 } 03072 03073 /* Clears all markers on the specified line between two points. If the group or 03074 flags fields are non-zero the returned flag must be in the specified group 03075 and have at least the specified flags set. */ 03076 short txt_clear_marker_region(Text *text, TextLine *line, int start, int end, int group, int flags) 03077 { 03078 TextMarker *marker, *next; 03079 int lineno= txt_get_span(text->lines.first, line); 03080 short cleared= 0; 03081 03082 for (marker=text->markers.first; marker; marker=next) { 03083 next= marker->next; 03084 03085 if (group && marker->group != group) continue; 03086 else if ((marker->flags & flags) != flags) continue; 03087 else if (marker->lineno < lineno) continue; 03088 else if (marker->lineno > lineno) break; 03089 03090 if ((marker->start==marker->end && start<=marker->start && marker->start<=end) || 03091 (marker->start<end && marker->end>start)) { 03092 BLI_freelinkN(&text->markers, marker); 03093 cleared= 1; 03094 } 03095 } 03096 return cleared; 03097 } 03098 03099 /* Clears all markers in the specified group (if given) with at least the 03100 specified flags set. Useful for clearing temporary markers (group=0, 03101 flags=TMARK_TEMP) */ 03102 short txt_clear_markers(Text *text, int group, int flags) 03103 { 03104 TextMarker *marker, *next; 03105 short cleared= 0; 03106 03107 for (marker=text->markers.first; marker; marker=next) { 03108 next= marker->next; 03109 03110 if ((!group || marker->group==group) && 03111 (marker->flags & flags) == flags) { 03112 BLI_freelinkN(&text->markers, marker); 03113 cleared= 1; 03114 } 03115 } 03116 return cleared; 03117 } 03118 03119 /* Finds the marker at the specified line and cursor position with at least the 03120 specified flags set in the given group (if non-zero). */ 03121 TextMarker *txt_find_marker(Text *text, TextLine *line, int curs, int group, int flags) 03122 { 03123 TextMarker *marker; 03124 int lineno= txt_get_span(text->lines.first, line); 03125 03126 for (marker=text->markers.first; marker; marker=marker->next) { 03127 if (group && marker->group != group) continue; 03128 else if ((marker->flags & flags) != flags) continue; 03129 else if (marker->lineno < lineno) continue; 03130 else if (marker->lineno > lineno) break; 03131 03132 if (marker->start <= curs && curs <= marker->end) 03133 return marker; 03134 } 03135 return NULL; 03136 } 03137 03138 /* Finds the previous marker in the same group. If no other is found, the same 03139 marker will be returned */ 03140 TextMarker *txt_prev_marker(Text *text, TextMarker *marker) 03141 { 03142 TextMarker *tmp= marker; 03143 while (tmp) { 03144 if (tmp->prev) tmp= tmp->prev; 03145 else tmp= text->markers.last; 03146 if (tmp->group == marker->group) 03147 return tmp; 03148 } 03149 return NULL; /* Only if marker==NULL */ 03150 } 03151 03152 /* Finds the next marker in the same group. If no other is found, the same 03153 marker will be returned */ 03154 TextMarker *txt_next_marker(Text *text, TextMarker *marker) 03155 { 03156 TextMarker *tmp= marker; 03157 while (tmp) { 03158 if (tmp->next) tmp= tmp->next; 03159 else tmp= text->markers.first; 03160 if (tmp->group == marker->group) 03161 return tmp; 03162 } 03163 return NULL; /* Only if marker==NULL */ 03164 } 03165 03166 03167 /*******************************/ 03168 /* Character utility functions */ 03169 /*******************************/ 03170 03171 int text_check_bracket(char ch) 03172 { 03173 int a; 03174 char opens[] = "([{"; 03175 char close[] = ")]}"; 03176 03177 for(a=0; a<(sizeof(opens)-1); a++) { 03178 if(ch==opens[a]) 03179 return a+1; 03180 else if(ch==close[a]) 03181 return -(a+1); 03182 } 03183 return 0; 03184 } 03185 03186 int text_check_delim(char ch) 03187 { 03188 int a; 03189 char delims[] = "():\"\' ~!%^&*-+=[]{};/<>|.#\t,"; 03190 03191 for(a=0; a<(sizeof(delims)-1); a++) { 03192 if(ch==delims[a]) 03193 return 1; 03194 } 03195 return 0; 03196 } 03197 03198 int text_check_digit(char ch) 03199 { 03200 if(ch < '0') return 0; 03201 if(ch <= '9') return 1; 03202 return 0; 03203 } 03204 03205 int text_check_identifier(char ch) 03206 { 03207 if(ch < '0') return 0; 03208 if(ch <= '9') return 1; 03209 if(ch < 'A') return 0; 03210 if(ch <= 'Z' || ch == '_') return 1; 03211 if(ch < 'a') return 0; 03212 if(ch <= 'z') return 1; 03213 return 0; 03214 } 03215 03216 int text_check_whitespace(char ch) 03217 { 03218 if(ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n') 03219 return 1; 03220 return 0; 03221 }