PageRenderTime 74ms CodeModel.GetById 29ms RepoModel.GetById 1ms app.codeStats 0ms

/blender-2.63a/source/blender/blenkernel/intern/text.c

#
C | 3279 lines | 2436 code | 621 blank | 222 comment | 647 complexity | ffea1e1e393d3ea7d5ded6b05f2fac4a MD5 | raw file
Possible License(s): GPL-3.0, GPL-2.0, BSD-3-Clause, LGPL-3.0, BSD-2-Clause, Apache-2.0, AGPL-1.0
  1. /*
  2. * ***** BEGIN GPL LICENSE BLOCK *****
  3. *
  4. * This program is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU General Public License
  6. * as published by the Free Software Foundation; either version 2
  7. * of the License, or (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program; if not, write to the Free Software Foundation,
  16. * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  17. *
  18. * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
  19. * All rights reserved.
  20. *
  21. * The Original Code is: all of this file.
  22. *
  23. * Contributor(s): none yet.
  24. *
  25. * ***** END GPL LICENSE BLOCK *****
  26. */
  27. /** \file blender/blenkernel/intern/text.c
  28. * \ingroup bke
  29. */
  30. #include <stdlib.h> /* abort */
  31. #include <string.h> /* strstr */
  32. #include <sys/types.h>
  33. #include <sys/stat.h>
  34. #include <wchar.h>
  35. #include <wctype.h>
  36. #include "MEM_guardedalloc.h"
  37. #include "BLI_path_util.h"
  38. #include "BLI_string.h"
  39. #include "BLI_string_cursor_utf8.h"
  40. #include "BLI_string_utf8.h"
  41. #include "BLI_listbase.h"
  42. #include "BLI_utildefines.h"
  43. #include "BLI_fileops.h"
  44. #include "DNA_constraint_types.h"
  45. #include "DNA_controller_types.h"
  46. #include "DNA_scene_types.h"
  47. #include "DNA_screen_types.h"
  48. #include "DNA_space_types.h"
  49. #include "DNA_text_types.h"
  50. #include "DNA_userdef_types.h"
  51. #include "DNA_object_types.h"
  52. #include "BKE_depsgraph.h"
  53. #include "BKE_global.h"
  54. #include "BKE_library.h"
  55. #include "BKE_main.h"
  56. #include "BKE_text.h"
  57. #ifdef WITH_PYTHON
  58. #include "BPY_extern.h"
  59. #endif
  60. /*
  61. * How Texts should work
  62. * --
  63. * A text should relate to a file as follows -
  64. * (Text *)->name should be the place where the
  65. * file will or has been saved.
  66. *
  67. * (Text *)->flags has the following bits
  68. * TXT_ISDIRTY - should always be set if the file in mem. differs from
  69. * the file on disk, or if there is no file on disk.
  70. * TXT_ISMEM - should always be set if the Text has not been mapped to
  71. * a file, in which case (Text *)->name may be NULL or garbage.
  72. * TXT_ISEXT - should always be set if the Text is not to be written into
  73. * the .blend
  74. * TXT_ISSCRIPT - should be set if the user has designated the text
  75. * as a script. (NEW: this was unused, but now it is needed by
  76. * space handler script links (see header_view3d.c, for example)
  77. *
  78. * ->>> see also: /makesdna/DNA_text_types.h
  79. *
  80. * Display
  81. * --
  82. * The st->top determines at what line the top of the text is displayed.
  83. * If the user moves the cursor the st containing that cursor should
  84. * be popped ... other st's retain their own top location.
  85. *
  86. * Markers
  87. * --
  88. * The mrk->flags define the behavior and relationships between markers. The
  89. * upper two bytes are used to hold a group ID, the lower two are normal flags. If
  90. * TMARK_EDITALL is set the group ID defines which other markers should be edited.
  91. *
  92. * The mrk->clr field is used to visually group markers where the flags may not
  93. * match. A template system, for example, may allow editing of repeating tokens
  94. * (in one group) but include other marked positions (in another group) all in the
  95. * same template with the same color.
  96. *
  97. * Undo
  98. * --
  99. * Undo/Redo works by storing
  100. * events in a queue, and a pointer
  101. * to the current position in the
  102. * queue...
  103. *
  104. * Events are stored using an
  105. * arbitrary op-code system
  106. * to keep track of
  107. * a) the two cursors (normal and selected)
  108. * b) input (visible and control (ie backspace))
  109. *
  110. * input data is stored as its
  111. * ASCII value, the opcodes are
  112. * then selected to not conflict.
  113. *
  114. * opcodes with data in between are
  115. * written at the beginning and end
  116. * of the data to allow undo and redo
  117. * to simply check the code at the current
  118. * undo position
  119. *
  120. */
  121. /***/
  122. static void txt_pop_first(Text *text);
  123. static void txt_pop_last(Text *text);
  124. static void txt_undo_add_op(Text *text, int op);
  125. static void txt_undo_add_block(Text *text, int op, const char *buf);
  126. static void txt_delete_line(Text *text, TextLine *line);
  127. static void txt_delete_sel (Text *text);
  128. static void txt_make_dirty (Text *text);
  129. /***/
  130. static unsigned char undoing;
  131. /* allow to switch off undoing externally */
  132. void txt_set_undostate(int u)
  133. {
  134. undoing = u;
  135. }
  136. int txt_get_undostate(void)
  137. {
  138. return undoing;
  139. }
  140. static void init_undo_text(Text *text)
  141. {
  142. text->undo_pos= -1;
  143. text->undo_len= TXT_INIT_UNDO;
  144. text->undo_buf= MEM_mallocN(text->undo_len, "undo buf");
  145. }
  146. void free_text(Text *text)
  147. {
  148. TextLine *tmp;
  149. for (tmp= text->lines.first; tmp; tmp= tmp->next) {
  150. MEM_freeN(tmp->line);
  151. if (tmp->format)
  152. MEM_freeN(tmp->format);
  153. }
  154. BLI_freelistN(&text->lines);
  155. BLI_freelistN(&text->markers);
  156. if (text->name) MEM_freeN(text->name);
  157. MEM_freeN(text->undo_buf);
  158. #ifdef WITH_PYTHON
  159. if (text->compiled) BPY_text_free_code(text);
  160. #endif
  161. }
  162. Text *add_empty_text(const char *name)
  163. {
  164. Main *bmain= G.main;
  165. Text *ta;
  166. TextLine *tmp;
  167. ta= alloc_libblock(&bmain->text, ID_TXT, name);
  168. ta->id.us= 1;
  169. ta->name= NULL;
  170. init_undo_text(ta);
  171. ta->nlines=1;
  172. ta->flags= TXT_ISDIRTY | TXT_ISMEM;
  173. if ((U.flag & USER_TXT_TABSTOSPACES_DISABLE)==0)
  174. ta->flags |= TXT_TABSTOSPACES;
  175. ta->lines.first= ta->lines.last= NULL;
  176. ta->markers.first= ta->markers.last= NULL;
  177. tmp= (TextLine*) MEM_mallocN(sizeof(TextLine), "textline");
  178. tmp->line= (char*) MEM_mallocN(1, "textline_string");
  179. tmp->format= NULL;
  180. tmp->line[0]=0;
  181. tmp->len= 0;
  182. tmp->next= NULL;
  183. tmp->prev= NULL;
  184. BLI_addhead(&ta->lines, tmp);
  185. ta->curl= ta->lines.first;
  186. ta->curc= 0;
  187. ta->sell= ta->lines.first;
  188. ta->selc= 0;
  189. return ta;
  190. }
  191. /* this function replaces extended ascii characters */
  192. /* to a valid utf-8 sequences */
  193. int txt_extended_ascii_as_utf8(char **str)
  194. {
  195. int bad_char, added= 0, i= 0;
  196. int length = strlen(*str);
  197. while ((*str)[i]) {
  198. if ((bad_char= BLI_utf8_invalid_byte(*str+i, length-i)) == -1)
  199. break;
  200. added++;
  201. i+= bad_char + 1;
  202. }
  203. if (added != 0) {
  204. char *newstr = MEM_mallocN(length+added+1, "text_line");
  205. int mi = 0;
  206. i= 0;
  207. while ((*str)[i]) {
  208. if ((bad_char= BLI_utf8_invalid_byte((*str)+i, length-i)) == -1) {
  209. memcpy(newstr+mi, (*str)+i, length - i + 1);
  210. break;
  211. }
  212. memcpy(newstr+mi, (*str)+i, bad_char);
  213. BLI_str_utf8_from_unicode((*str)[i+bad_char], newstr+mi+bad_char);
  214. i+= bad_char+1;
  215. mi+= bad_char+2;
  216. }
  217. newstr[length+added] = '\0';
  218. MEM_freeN(*str);
  219. *str = newstr;
  220. }
  221. return added;
  222. }
  223. // this function removes any control characters from
  224. // a textline and fixes invalid utf-8 sequences
  225. static void cleanup_textline(TextLine * tl)
  226. {
  227. int i;
  228. for (i = 0; i < tl->len; i++ ) {
  229. if (tl->line[i] < ' ' && tl->line[i] != '\t') {
  230. memmove(tl->line + i, tl->line + i + 1, tl->len - i);
  231. tl->len--;
  232. i--;
  233. }
  234. }
  235. tl->len+= txt_extended_ascii_as_utf8(&tl->line);
  236. }
  237. int reopen_text(Text *text)
  238. {
  239. FILE *fp;
  240. int i, llen, len;
  241. unsigned char *buffer;
  242. TextLine *tmp;
  243. char str[FILE_MAX];
  244. struct stat st;
  245. if (!text || !text->name) return 0;
  246. BLI_strncpy(str, text->name, FILE_MAX);
  247. BLI_path_abs(str, G.main->name);
  248. fp= BLI_fopen(str, "r");
  249. if (fp==NULL) return 0;
  250. /* free memory: */
  251. for (tmp= text->lines.first; tmp; tmp= tmp->next) {
  252. MEM_freeN(tmp->line);
  253. if (tmp->format) MEM_freeN(tmp->format);
  254. }
  255. BLI_freelistN(&text->lines);
  256. text->lines.first= text->lines.last= NULL;
  257. text->curl= text->sell= NULL;
  258. /* clear undo buffer */
  259. MEM_freeN(text->undo_buf);
  260. init_undo_text(text);
  261. fseek(fp, 0L, SEEK_END);
  262. len= ftell(fp);
  263. fseek(fp, 0L, SEEK_SET);
  264. text->undo_pos= -1;
  265. buffer= MEM_mallocN(len, "text_buffer");
  266. // under windows fread can return less then len bytes because
  267. // of CR stripping
  268. len = fread(buffer, 1, len, fp);
  269. fclose(fp);
  270. stat(str, &st);
  271. text->mtime= st.st_mtime;
  272. text->nlines=0;
  273. llen=0;
  274. for (i=0; i<len; i++) {
  275. if (buffer[i]=='\n') {
  276. tmp= (TextLine*) MEM_mallocN(sizeof(TextLine), "textline");
  277. tmp->line= (char*) MEM_mallocN(llen+1, "textline_string");
  278. tmp->format= NULL;
  279. if (llen) memcpy(tmp->line, &buffer[i-llen], llen);
  280. tmp->line[llen]=0;
  281. tmp->len= llen;
  282. cleanup_textline(tmp);
  283. BLI_addtail(&text->lines, tmp);
  284. text->nlines++;
  285. llen=0;
  286. continue;
  287. }
  288. llen++;
  289. }
  290. if (llen!=0 || text->nlines==0) {
  291. tmp= (TextLine*) MEM_mallocN(sizeof(TextLine), "textline");
  292. tmp->line= (char*) MEM_mallocN(llen+1, "textline_string");
  293. tmp->format= NULL;
  294. if (llen) memcpy(tmp->line, &buffer[i-llen], llen);
  295. tmp->line[llen]=0;
  296. tmp->len= llen;
  297. cleanup_textline(tmp);
  298. BLI_addtail(&text->lines, tmp);
  299. text->nlines++;
  300. }
  301. text->curl= text->sell= text->lines.first;
  302. text->curc= text->selc= 0;
  303. MEM_freeN(buffer);
  304. return 1;
  305. }
  306. Text *add_text(const char *file, const char *relpath)
  307. {
  308. Main *bmain= G.main;
  309. FILE *fp;
  310. int i, llen, len;
  311. unsigned char *buffer;
  312. TextLine *tmp;
  313. Text *ta;
  314. char str[FILE_MAX];
  315. struct stat st;
  316. BLI_strncpy(str, file, FILE_MAX);
  317. if (relpath) /* can be NULL (bg mode) */
  318. BLI_path_abs(str, relpath);
  319. fp= BLI_fopen(str, "r");
  320. if (fp==NULL) return NULL;
  321. ta= alloc_libblock(&bmain->text, ID_TXT, BLI_path_basename(str));
  322. ta->id.us= 1;
  323. ta->lines.first= ta->lines.last= NULL;
  324. ta->markers.first= ta->markers.last= NULL;
  325. ta->curl= ta->sell= NULL;
  326. if ((U.flag & USER_TXT_TABSTOSPACES_DISABLE)==0)
  327. ta->flags= TXT_TABSTOSPACES;
  328. fseek(fp, 0L, SEEK_END);
  329. len= ftell(fp);
  330. fseek(fp, 0L, SEEK_SET);
  331. ta->name= MEM_mallocN(strlen(file)+1, "text_name");
  332. strcpy(ta->name, file);
  333. init_undo_text(ta);
  334. buffer= MEM_mallocN(len, "text_buffer");
  335. // under windows fread can return less then len bytes because
  336. // of CR stripping
  337. len = fread(buffer, 1, len, fp);
  338. fclose(fp);
  339. stat(str, &st);
  340. ta->mtime= st.st_mtime;
  341. ta->nlines=0;
  342. llen=0;
  343. for (i=0; i<len; i++) {
  344. if (buffer[i]=='\n') {
  345. tmp= (TextLine*) MEM_mallocN(sizeof(TextLine), "textline");
  346. tmp->line= (char*) MEM_mallocN(llen+1, "textline_string");
  347. tmp->format= NULL;
  348. if (llen) memcpy(tmp->line, &buffer[i-llen], llen);
  349. tmp->line[llen]=0;
  350. tmp->len= llen;
  351. cleanup_textline(tmp);
  352. BLI_addtail(&ta->lines, tmp);
  353. ta->nlines++;
  354. llen=0;
  355. continue;
  356. }
  357. llen++;
  358. }
  359. /* create new line in cases:
  360. * - rest of line (if last line in file hasn't got \n terminator).
  361. * in this case content of such line would be used to fill text line buffer
  362. * - file is empty. in this case new line is needed to start editing from.
  363. * - last characted in buffer is \n. in this case new line is needed to
  364. * deal with newline at end of file. (see [#28087]) (sergey) */
  365. if (llen!=0 || ta->nlines==0 || buffer[len-1]=='\n') {
  366. tmp= (TextLine*) MEM_mallocN(sizeof(TextLine), "textline");
  367. tmp->line= (char*) MEM_mallocN(llen+1, "textline_string");
  368. tmp->format= NULL;
  369. if (llen) memcpy(tmp->line, &buffer[i-llen], llen);
  370. tmp->line[llen]=0;
  371. tmp->len= llen;
  372. cleanup_textline(tmp);
  373. BLI_addtail(&ta->lines, tmp);
  374. ta->nlines++;
  375. }
  376. ta->curl= ta->sell= ta->lines.first;
  377. ta->curc= ta->selc= 0;
  378. MEM_freeN(buffer);
  379. return ta;
  380. }
  381. Text *copy_text(Text *ta)
  382. {
  383. Text *tan;
  384. TextLine *line, *tmp;
  385. tan= copy_libblock(&ta->id);
  386. /* file name can be NULL */
  387. if (ta->name) {
  388. tan->name= MEM_mallocN(strlen(ta->name)+1, "text_name");
  389. strcpy(tan->name, ta->name);
  390. }
  391. else {
  392. tan->name= NULL;
  393. }
  394. tan->flags = ta->flags | TXT_ISDIRTY;
  395. tan->lines.first= tan->lines.last= NULL;
  396. tan->markers.first= tan->markers.last= NULL;
  397. tan->curl= tan->sell= NULL;
  398. tan->nlines= ta->nlines;
  399. line= ta->lines.first;
  400. /* Walk down, reconstructing */
  401. while (line) {
  402. tmp= (TextLine*) MEM_mallocN(sizeof(TextLine), "textline");
  403. tmp->line= MEM_mallocN(line->len+1, "textline_string");
  404. tmp->format= NULL;
  405. strcpy(tmp->line, line->line);
  406. tmp->len= line->len;
  407. BLI_addtail(&tan->lines, tmp);
  408. line= line->next;
  409. }
  410. tan->curl= tan->sell= tan->lines.first;
  411. tan->curc= tan->selc= 0;
  412. init_undo_text(tan);
  413. return tan;
  414. }
  415. void unlink_text(Main *bmain, Text *text)
  416. {
  417. bScreen *scr;
  418. ScrArea *area;
  419. SpaceLink *sl;
  420. Object *ob;
  421. bController *cont;
  422. bConstraint *con;
  423. short update;
  424. for (ob=bmain->object.first; ob; ob=ob->id.next) {
  425. /* game controllers */
  426. for (cont=ob->controllers.first; cont; cont=cont->next) {
  427. if (cont->type==CONT_PYTHON) {
  428. bPythonCont *pc;
  429. pc= cont->data;
  430. if (pc->text==text) pc->text= NULL;
  431. }
  432. }
  433. /* pyconstraints */
  434. update = 0;
  435. if (ob->type==OB_ARMATURE && ob->pose) {
  436. bPoseChannel *pchan;
  437. for (pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
  438. for (con = pchan->constraints.first; con; con=con->next) {
  439. if (con->type==CONSTRAINT_TYPE_PYTHON) {
  440. bPythonConstraint *data = con->data;
  441. if (data->text==text) data->text = NULL;
  442. update = 1;
  443. }
  444. }
  445. }
  446. }
  447. for (con = ob->constraints.first; con; con=con->next) {
  448. if (con->type==CONSTRAINT_TYPE_PYTHON) {
  449. bPythonConstraint *data = con->data;
  450. if (data->text==text) data->text = NULL;
  451. update = 1;
  452. }
  453. }
  454. if (update)
  455. DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
  456. }
  457. /* pynodes */
  458. // XXX nodeDynamicUnlinkText(&text->id);
  459. /* text space */
  460. for (scr= bmain->screen.first; scr; scr= scr->id.next) {
  461. for (area= scr->areabase.first; area; area= area->next) {
  462. for (sl= area->spacedata.first; sl; sl= sl->next) {
  463. if (sl->spacetype==SPACE_TEXT) {
  464. SpaceText *st= (SpaceText*) sl;
  465. if (st->text==text) {
  466. st->text= NULL;
  467. st->top= 0;
  468. }
  469. }
  470. }
  471. }
  472. }
  473. text->id.us= 0;
  474. }
  475. void clear_text(Text *text) /* called directly from rna */
  476. {
  477. int oldstate;
  478. oldstate = txt_get_undostate( );
  479. txt_set_undostate( 1 );
  480. txt_sel_all( text );
  481. txt_delete_sel(text);
  482. txt_set_undostate(oldstate);
  483. txt_make_dirty(text);
  484. }
  485. void write_text(Text *text, const char *str) /* called directly from rna */
  486. {
  487. int oldstate;
  488. oldstate = txt_get_undostate();
  489. txt_insert_buf(text, str);
  490. txt_move_eof(text, 0);
  491. txt_set_undostate(oldstate);
  492. txt_make_dirty(text);
  493. }
  494. /*****************************/
  495. /* Editing utility functions */
  496. /*****************************/
  497. static void make_new_line(TextLine *line, char *newline)
  498. {
  499. if (line->line) MEM_freeN(line->line);
  500. if (line->format) MEM_freeN(line->format);
  501. line->line= newline;
  502. line->len= strlen(newline);
  503. line->format= NULL;
  504. }
  505. static TextLine *txt_new_line(const char *str)
  506. {
  507. TextLine *tmp;
  508. if (!str) str= "";
  509. tmp= (TextLine *) MEM_mallocN(sizeof(TextLine), "textline");
  510. tmp->line= MEM_mallocN(strlen(str)+1, "textline_string");
  511. tmp->format= NULL;
  512. strcpy(tmp->line, str);
  513. tmp->len= strlen(str);
  514. tmp->next= tmp->prev= NULL;
  515. return tmp;
  516. }
  517. static TextLine *txt_new_linen(const char *str, int n)
  518. {
  519. TextLine *tmp;
  520. tmp= (TextLine *) MEM_mallocN(sizeof(TextLine), "textline");
  521. tmp->line= MEM_mallocN(n+1, "textline_string");
  522. tmp->format= NULL;
  523. BLI_strncpy(tmp->line, (str)? str: "", n+1);
  524. tmp->len= strlen(tmp->line);
  525. tmp->next= tmp->prev= NULL;
  526. return tmp;
  527. }
  528. void txt_clean_text (Text *text)
  529. {
  530. TextLine **top, **bot;
  531. if (!text) return;
  532. if (!text->lines.first) {
  533. if (text->lines.last) text->lines.first= text->lines.last;
  534. else text->lines.first= text->lines.last= txt_new_line(NULL);
  535. }
  536. if (!text->lines.last) text->lines.last= text->lines.first;
  537. top= (TextLine **) &text->lines.first;
  538. bot= (TextLine **) &text->lines.last;
  539. while ((*top)->prev) *top= (*top)->prev;
  540. while ((*bot)->next) *bot= (*bot)->next;
  541. if (!text->curl) {
  542. if (text->sell) text->curl= text->sell;
  543. else text->curl= text->lines.first;
  544. text->curc= 0;
  545. }
  546. if (!text->sell) {
  547. text->sell= text->curl;
  548. text->selc= 0;
  549. }
  550. }
  551. int txt_get_span (TextLine *from, TextLine *to)
  552. {
  553. int ret=0;
  554. TextLine *tmp= from;
  555. if (!to || !from) return 0;
  556. if (from==to) return 0;
  557. /* Look forwards */
  558. while (tmp) {
  559. if (tmp == to) return ret;
  560. ret++;
  561. tmp= tmp->next;
  562. }
  563. /* Look backwards */
  564. if (!tmp) {
  565. tmp= from;
  566. ret=0;
  567. while (tmp) {
  568. if (tmp == to) break;
  569. ret--;
  570. tmp= tmp->prev;
  571. }
  572. if (!tmp) ret=0;
  573. }
  574. return ret;
  575. }
  576. static void txt_make_dirty (Text *text)
  577. {
  578. text->flags |= TXT_ISDIRTY;
  579. #ifdef WITH_PYTHON
  580. if (text->compiled) BPY_text_free_code(text);
  581. #endif
  582. }
  583. /****************************/
  584. /* Cursor utility functions */
  585. /****************************/
  586. static void txt_curs_cur (Text *text, TextLine ***linep, int **charp)
  587. {
  588. *linep= &text->curl; *charp= &text->curc;
  589. }
  590. static void txt_curs_sel (Text *text, TextLine ***linep, int **charp)
  591. {
  592. *linep= &text->sell; *charp= &text->selc;
  593. }
  594. static void txt_curs_first (Text *text, TextLine **linep, int *charp)
  595. {
  596. if (text->curl==text->sell) {
  597. *linep= text->curl;
  598. if (text->curc<text->selc) *charp= text->curc;
  599. else *charp= text->selc;
  600. }
  601. else if (txt_get_span(text->lines.first, text->curl)<txt_get_span(text->lines.first, text->sell)) {
  602. *linep= text->curl;
  603. *charp= text->curc;
  604. }
  605. else {
  606. *linep= text->sell;
  607. *charp= text->selc;
  608. }
  609. }
  610. /*****************************/
  611. /* Cursor movement functions */
  612. /*****************************/
  613. int txt_utf8_offset_to_index(const char *str, int offset)
  614. {
  615. int index= 0, pos= 0;
  616. while (pos != offset) {
  617. pos += BLI_str_utf8_size(str + pos);
  618. index++;
  619. }
  620. return index;
  621. }
  622. int txt_utf8_index_to_offset(const char *str, int index)
  623. {
  624. int offset= 0, pos= 0;
  625. while (pos != index) {
  626. offset += BLI_str_utf8_size(str + offset);
  627. pos++;
  628. }
  629. return offset;
  630. }
  631. /* returns the real number of characters in string */
  632. /* not the same as BLI_strlen_utf8, which returns length for wide characters */
  633. static int txt_utf8_len(const char *src)
  634. {
  635. int len;
  636. for (len=0; *src; len++) {
  637. src += BLI_str_utf8_size(src);
  638. }
  639. return len;
  640. }
  641. void txt_move_up(Text *text, short sel)
  642. {
  643. TextLine **linep;
  644. int *charp;
  645. /* int old; */ /* UNUSED */
  646. if (!text) return;
  647. if (sel) txt_curs_sel(text, &linep, &charp);
  648. else { txt_pop_first(text); txt_curs_cur(text, &linep, &charp); }
  649. if (!*linep) return;
  650. /* old= *charp; */ /* UNUSED */
  651. if ((*linep)->prev) {
  652. int index = txt_utf8_offset_to_index((*linep)->line, *charp);
  653. *linep= (*linep)->prev;
  654. if (index > txt_utf8_len((*linep)->line)) *charp= (*linep)->len;
  655. else *charp= txt_utf8_index_to_offset((*linep)->line, index);
  656. if (!undoing)
  657. txt_undo_add_op(text, sel?UNDO_SUP:UNDO_CUP);
  658. }
  659. else {
  660. txt_move_bol(text, sel);
  661. }
  662. if (!sel) txt_pop_sel(text);
  663. }
  664. void txt_move_down(Text *text, short sel)
  665. {
  666. TextLine **linep;
  667. int *charp;
  668. /* int old; */ /* UNUSED */
  669. if (!text) return;
  670. if (sel) txt_curs_sel(text, &linep, &charp);
  671. else { txt_pop_last(text); txt_curs_cur(text, &linep, &charp); }
  672. if (!*linep) return;
  673. /* old= *charp; */ /* UNUSED */
  674. if ((*linep)->next) {
  675. int index = txt_utf8_offset_to_index((*linep)->line, *charp);
  676. *linep= (*linep)->next;
  677. if (index > txt_utf8_len((*linep)->line)) *charp= (*linep)->len;
  678. else *charp= txt_utf8_index_to_offset((*linep)->line, index);
  679. if (!undoing)
  680. txt_undo_add_op(text, sel?UNDO_SDOWN:UNDO_CDOWN);
  681. }
  682. else {
  683. txt_move_eol(text, sel);
  684. }
  685. if (!sel) txt_pop_sel(text);
  686. }
  687. void txt_move_left(Text *text, short sel)
  688. {
  689. TextLine **linep;
  690. int *charp, oundoing= undoing;
  691. int tabsize= 0, i= 0;
  692. if (!text) return;
  693. if (sel) txt_curs_sel(text, &linep, &charp);
  694. else { txt_pop_first(text); txt_curs_cur(text, &linep, &charp); }
  695. if (!*linep) return;
  696. undoing= 1;
  697. if (*charp== 0) {
  698. if ((*linep)->prev) {
  699. txt_move_up(text, sel);
  700. *charp= (*linep)->len;
  701. }
  702. }
  703. else {
  704. // do nice left only if there are only spaces
  705. // TXT_TABSIZE hardcoded in DNA_text_types.h
  706. if (text->flags & TXT_TABSTOSPACES) {
  707. tabsize= (*charp < TXT_TABSIZE) ? *charp : TXT_TABSIZE;
  708. for (i=0; i<(*charp); i++)
  709. if ((*linep)->line[i] != ' ') {
  710. tabsize= 0;
  711. break;
  712. }
  713. // if in the middle of the space-tab
  714. if (tabsize && (*charp) % TXT_TABSIZE != 0)
  715. tabsize= ((*charp) % TXT_TABSIZE);
  716. }
  717. if (tabsize)
  718. (*charp)-= tabsize;
  719. else {
  720. const char *prev= BLI_str_prev_char_utf8((*linep)->line + *charp);
  721. *charp= prev - (*linep)->line;
  722. }
  723. }
  724. undoing= oundoing;
  725. if (!undoing) txt_undo_add_op(text, sel?UNDO_SLEFT:UNDO_CLEFT);
  726. if (!sel) txt_pop_sel(text);
  727. }
  728. void txt_move_right(Text *text, short sel)
  729. {
  730. TextLine **linep;
  731. int *charp, oundoing= undoing, do_tab= 0, i;
  732. if (!text) return;
  733. if (sel) txt_curs_sel(text, &linep, &charp);
  734. else { txt_pop_last(text); txt_curs_cur(text, &linep, &charp); }
  735. if (!*linep) return;
  736. undoing= 1;
  737. if (*charp== (*linep)->len) {
  738. if ((*linep)->next) {
  739. txt_move_down(text, sel);
  740. *charp= 0;
  741. }
  742. }
  743. else {
  744. // do nice right only if there are only spaces
  745. // spaces hardcoded in DNA_text_types.h
  746. if (text->flags & TXT_TABSTOSPACES && (*linep)->line[*charp]== ' ') {
  747. do_tab= 1;
  748. for (i=0; i<*charp; i++)
  749. if ((*linep)->line[i]!= ' ') {
  750. do_tab= 0;
  751. break;
  752. }
  753. }
  754. if (do_tab) {
  755. int tabsize= (*charp) % TXT_TABSIZE + 1;
  756. for (i=*charp+1; (*linep)->line[i]==' ' && tabsize<TXT_TABSIZE; i++)
  757. tabsize++;
  758. (*charp)= i;
  759. }
  760. else (*charp)+= BLI_str_utf8_size((*linep)->line + *charp);
  761. }
  762. undoing= oundoing;
  763. if (!undoing) txt_undo_add_op(text, sel?UNDO_SRIGHT:UNDO_CRIGHT);
  764. if (!sel) txt_pop_sel(text);
  765. }
  766. void txt_jump_left(Text *text, short sel)
  767. {
  768. TextLine **linep;
  769. int *charp, oldc;
  770. if (!text) return;
  771. if (sel) txt_curs_sel(text, &linep, &charp);
  772. else { txt_pop_first(text); txt_curs_cur(text, &linep, &charp); }
  773. if (!*linep) return;
  774. oldc = *charp;
  775. BLI_str_cursor_step_utf8((*linep)->line, (*linep)->len,
  776. charp, STRCUR_DIR_PREV,
  777. STRCUR_JUMP_DELIM);
  778. if (!sel) txt_pop_sel(text);
  779. if (!undoing) {
  780. int span = txt_get_span(text->lines.first, *linep);
  781. txt_undo_add_toop(text, sel ? UNDO_STO : UNDO_CTO, span, oldc, span, (unsigned short)*charp);
  782. }
  783. }
  784. void txt_jump_right(Text *text, short sel)
  785. {
  786. TextLine **linep;
  787. int *charp, oldc;
  788. if (!text) return;
  789. if (sel) txt_curs_sel(text, &linep, &charp);
  790. else { txt_pop_last(text); txt_curs_cur(text, &linep, &charp); }
  791. if (!*linep) return;
  792. oldc = *charp;
  793. BLI_str_cursor_step_utf8((*linep)->line, (*linep)->len,
  794. charp, STRCUR_DIR_NEXT,
  795. STRCUR_JUMP_DELIM);
  796. if (!sel) txt_pop_sel(text);
  797. if (!undoing) {
  798. int span = txt_get_span(text->lines.first, *linep);
  799. txt_undo_add_toop(text, sel ? UNDO_STO : UNDO_CTO, span, oldc, span, (unsigned short)*charp);
  800. }
  801. }
  802. void txt_move_bol (Text *text, short sel)
  803. {
  804. TextLine **linep;
  805. int *charp, old;
  806. if (!text) return;
  807. if (sel) txt_curs_sel(text, &linep, &charp);
  808. else txt_curs_cur(text, &linep, &charp);
  809. if (!*linep) return;
  810. old= *charp;
  811. *charp= 0;
  812. if (!sel) txt_pop_sel(text);
  813. 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);
  814. }
  815. void txt_move_eol (Text *text, short sel)
  816. {
  817. TextLine **linep;
  818. int *charp, old;
  819. if (!text) return;
  820. if (sel) txt_curs_sel(text, &linep, &charp);
  821. else txt_curs_cur(text, &linep, &charp);
  822. if (!*linep) return;
  823. old= *charp;
  824. *charp= (*linep)->len;
  825. if (!sel) txt_pop_sel(text);
  826. 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);
  827. }
  828. void txt_move_bof (Text *text, short sel)
  829. {
  830. TextLine **linep;
  831. int *charp, old;
  832. if (!text) return;
  833. if (sel) txt_curs_sel(text, &linep, &charp);
  834. else txt_curs_cur(text, &linep, &charp);
  835. if (!*linep) return;
  836. old= *charp;
  837. *linep= text->lines.first;
  838. *charp= 0;
  839. if (!sel) txt_pop_sel(text);
  840. 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);
  841. }
  842. void txt_move_eof (Text *text, short sel)
  843. {
  844. TextLine **linep;
  845. int *charp, old;
  846. if (!text) return;
  847. if (sel) txt_curs_sel(text, &linep, &charp);
  848. else txt_curs_cur(text, &linep, &charp);
  849. if (!*linep) return;
  850. old= *charp;
  851. *linep= text->lines.last;
  852. *charp= (*linep)->len;
  853. if (!sel) txt_pop_sel(text);
  854. 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);
  855. }
  856. void txt_move_toline (Text *text, unsigned int line, short sel)
  857. {
  858. txt_move_to(text, line, 0, sel);
  859. }
  860. /* Moves to a certain byte in a line, not a certain utf8-character! */
  861. void txt_move_to (Text *text, unsigned int line, unsigned int ch, short sel)
  862. {
  863. TextLine **linep, *oldl;
  864. int *charp, oldc;
  865. unsigned int i;
  866. if (!text) return;
  867. if (sel) txt_curs_sel(text, &linep, &charp);
  868. else txt_curs_cur(text, &linep, &charp);
  869. if (!*linep) return;
  870. oldc= *charp;
  871. oldl= *linep;
  872. *linep= text->lines.first;
  873. for (i=0; i<line; i++) {
  874. if ((*linep)->next) *linep= (*linep)->next;
  875. else break;
  876. }
  877. if (ch>(unsigned int)((*linep)->len))
  878. ch= (unsigned int)((*linep)->len);
  879. *charp= ch;
  880. if (!sel) txt_pop_sel(text);
  881. 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);
  882. }
  883. /****************************/
  884. /* Text selection functions */
  885. /****************************/
  886. static void txt_curs_swap (Text *text)
  887. {
  888. TextLine *tmpl;
  889. int tmpc;
  890. tmpl= text->curl;
  891. text->curl= text->sell;
  892. text->sell= tmpl;
  893. tmpc= text->curc;
  894. text->curc= text->selc;
  895. text->selc= tmpc;
  896. if (!undoing) txt_undo_add_op(text, UNDO_SWAP);
  897. }
  898. static void txt_pop_first (Text *text)
  899. {
  900. if (txt_get_span(text->curl, text->sell)<0 ||
  901. (text->curl==text->sell && text->curc>text->selc)) {
  902. txt_curs_swap(text);
  903. }
  904. if (!undoing) txt_undo_add_toop(text, UNDO_STO,
  905. txt_get_span(text->lines.first, text->sell),
  906. text->selc,
  907. txt_get_span(text->lines.first, text->curl),
  908. text->curc);
  909. txt_pop_sel(text);
  910. }
  911. static void txt_pop_last (Text *text)
  912. {
  913. if (txt_get_span(text->curl, text->sell)>0 ||
  914. (text->curl==text->sell && text->curc<text->selc)) {
  915. txt_curs_swap(text);
  916. }
  917. if (!undoing) txt_undo_add_toop(text, UNDO_STO,
  918. txt_get_span(text->lines.first, text->sell),
  919. text->selc,
  920. txt_get_span(text->lines.first, text->curl),
  921. text->curc);
  922. txt_pop_sel(text);
  923. }
  924. /* never used: CVS 1.19 */
  925. /* static void txt_pop_selr (Text *text) */
  926. void txt_pop_sel (Text *text)
  927. {
  928. text->sell= text->curl;
  929. text->selc= text->curc;
  930. }
  931. void txt_order_cursors(Text *text)
  932. {
  933. if (!text) return;
  934. if (!text->curl) return;
  935. if (!text->sell) return;
  936. /* Flip so text->curl is before text->sell */
  937. if (txt_get_span(text->curl, text->sell)<0 ||
  938. (text->curl==text->sell && text->curc>text->selc))
  939. txt_curs_swap(text);
  940. }
  941. int txt_has_sel(Text *text)
  942. {
  943. return ((text->curl!=text->sell) || (text->curc!=text->selc));
  944. }
  945. static void txt_delete_sel (Text *text)
  946. {
  947. TextLine *tmpl;
  948. TextMarker *mrk;
  949. char *buf;
  950. int move, lineno;
  951. if (!text) return;
  952. if (!text->curl) return;
  953. if (!text->sell) return;
  954. if (!txt_has_sel(text)) return;
  955. txt_order_cursors(text);
  956. if (!undoing) {
  957. buf= txt_sel_to_buf(text);
  958. txt_undo_add_block(text, UNDO_DBLOCK, buf);
  959. MEM_freeN(buf);
  960. }
  961. buf= MEM_mallocN(text->curc+(text->sell->len - text->selc)+1, "textline_string");
  962. if (text->curl != text->sell) {
  963. txt_clear_marker_region(text, text->curl, text->curc, text->curl->len, 0, 0);
  964. move= txt_get_span(text->curl, text->sell);
  965. }
  966. else {
  967. mrk= txt_find_marker_region(text, text->curl, text->curc, text->selc, 0, 0);
  968. if (mrk && (mrk->start > text->curc || mrk->end < text->selc))
  969. txt_clear_marker_region(text, text->curl, text->curc, text->selc, 0, 0);
  970. move= 0;
  971. }
  972. mrk= txt_find_marker_region(text, text->sell, text->selc-1, text->sell->len, 0, 0);
  973. if (mrk) {
  974. lineno= mrk->lineno;
  975. do {
  976. mrk->lineno -= move;
  977. if (mrk->start > text->curc) mrk->start -= text->selc - text->curc;
  978. mrk->end -= text->selc - text->curc;
  979. mrk= mrk->next;
  980. } while (mrk && mrk->lineno==lineno);
  981. }
  982. strncpy(buf, text->curl->line, text->curc);
  983. strcpy(buf+text->curc, text->sell->line + text->selc);
  984. buf[text->curc+(text->sell->len - text->selc)]=0;
  985. make_new_line(text->curl, buf);
  986. tmpl= text->sell;
  987. while (tmpl != text->curl) {
  988. tmpl= tmpl->prev;
  989. if (!tmpl) break;
  990. txt_delete_line(text, tmpl->next);
  991. }
  992. text->sell= text->curl;
  993. text->selc= text->curc;
  994. }
  995. void txt_sel_all (Text *text)
  996. {
  997. if (!text) return;
  998. text->curl= text->lines.first;
  999. text->curc= 0;
  1000. text->sell= text->lines.last;
  1001. text->selc= text->sell->len;
  1002. }
  1003. void txt_sel_line (Text *text)
  1004. {
  1005. if (!text) return;
  1006. if (!text->curl) return;
  1007. text->curc= 0;
  1008. text->sell= text->curl;
  1009. text->selc= text->sell->len;
  1010. }
  1011. /***************************/
  1012. /* Cut and paste functions */
  1013. /***************************/
  1014. char *txt_to_buf (Text *text)
  1015. {
  1016. int length;
  1017. TextLine *tmp, *linef, *linel;
  1018. int charf, charl;
  1019. char *buf;
  1020. if (!text) return NULL;
  1021. if (!text->curl) return NULL;
  1022. if (!text->sell) return NULL;
  1023. if (!text->lines.first) return NULL;
  1024. linef= text->lines.first;
  1025. charf= 0;
  1026. linel= text->lines.last;
  1027. charl= linel->len;
  1028. if (linef == text->lines.last) {
  1029. length= charl-charf;
  1030. buf= MEM_mallocN(length+2, "text buffer");
  1031. BLI_strncpy(buf, linef->line + charf, length+1);
  1032. buf[length]=0;
  1033. }
  1034. else {
  1035. length= linef->len - charf;
  1036. length+= charl;
  1037. length+= 2; /* For the 2 '\n' */
  1038. tmp= linef->next;
  1039. while (tmp && tmp!= linel) {
  1040. length+= tmp->len+1;
  1041. tmp= tmp->next;
  1042. }
  1043. buf= MEM_mallocN(length+1, "cut buffer");
  1044. strncpy(buf, linef->line + charf, linef->len-charf);
  1045. length= linef->len - charf;
  1046. buf[length++]='\n';
  1047. tmp= linef->next;
  1048. while (tmp && tmp!=linel) {
  1049. strncpy(buf+length, tmp->line, tmp->len);
  1050. length+= tmp->len;
  1051. buf[length++]='\n';
  1052. tmp= tmp->next;
  1053. }
  1054. strncpy(buf+length, linel->line, charl);
  1055. length+= charl;
  1056. /* python compiler wants an empty end line */
  1057. buf[length++]='\n';
  1058. buf[length]=0;
  1059. }
  1060. return buf;
  1061. }
  1062. int txt_find_string(Text *text, const char *findstr, int wrap, int match_case)
  1063. {
  1064. TextLine *tl, *startl;
  1065. char *s= NULL;
  1066. if (!text || !text->curl || !text->sell) return 0;
  1067. txt_order_cursors(text);
  1068. tl= startl= text->sell;
  1069. if (match_case) s= strstr(&tl->line[text->selc], findstr);
  1070. else s= BLI_strcasestr(&tl->line[text->selc], findstr);
  1071. while (!s) {
  1072. tl= tl->next;
  1073. if (!tl) {
  1074. if (wrap)
  1075. tl= text->lines.first;
  1076. else
  1077. break;
  1078. }
  1079. if (match_case) s= strstr(tl->line, findstr);
  1080. else s= BLI_strcasestr(tl->line, findstr);
  1081. if (tl==startl)
  1082. break;
  1083. }
  1084. if (s) {
  1085. int newl= txt_get_span(text->lines.first, tl);
  1086. int newc= (int)(s-tl->line);
  1087. txt_move_to(text, newl, newc, 0);
  1088. txt_move_to(text, newl, newc + strlen(findstr), 1);
  1089. return 1;
  1090. }
  1091. else
  1092. return 0;
  1093. }
  1094. char *txt_sel_to_buf (Text *text)
  1095. {
  1096. char *buf;
  1097. int length=0;
  1098. TextLine *tmp, *linef, *linel;
  1099. int charf, charl;
  1100. if (!text) return NULL;
  1101. if (!text->curl) return NULL;
  1102. if (!text->sell) return NULL;
  1103. if (text->curl==text->sell) {
  1104. linef= linel= text->curl;
  1105. if (text->curc < text->selc) {
  1106. charf= text->curc;
  1107. charl= text->selc;
  1108. }
  1109. else {
  1110. charf= text->selc;
  1111. charl= text->curc;
  1112. }
  1113. }
  1114. else if (txt_get_span(text->curl, text->sell)<0) {
  1115. linef= text->sell;
  1116. linel= text->curl;
  1117. charf= text->selc;
  1118. charl= text->curc;
  1119. }
  1120. else {
  1121. linef= text->curl;
  1122. linel= text->sell;
  1123. charf= text->curc;
  1124. charl= text->selc;
  1125. }
  1126. if (linef == linel) {
  1127. length= charl-charf;
  1128. buf= MEM_mallocN(length+1, "sel buffer");
  1129. BLI_strncpy(buf, linef->line + charf, length+1);
  1130. }
  1131. else {
  1132. length+= linef->len - charf;
  1133. length+= charl;
  1134. length++; /* For the '\n' */
  1135. tmp= linef->next;
  1136. while (tmp && tmp!= linel) {
  1137. length+= tmp->len+1;
  1138. tmp= tmp->next;
  1139. }
  1140. buf= MEM_mallocN(length+1, "sel buffer");
  1141. strncpy(buf, linef->line+ charf, linef->len-charf);
  1142. length= linef->len-charf;
  1143. buf[length++]='\n';
  1144. tmp= linef->next;
  1145. while (tmp && tmp!=linel) {
  1146. strncpy(buf+length, tmp->line, tmp->len);
  1147. length+= tmp->len;
  1148. buf[length++]='\n';
  1149. tmp= tmp->next;
  1150. }
  1151. strncpy(buf+length, linel->line, charl);
  1152. length+= charl;
  1153. buf[length]=0;
  1154. }
  1155. return buf;
  1156. }
  1157. static void txt_shift_markers(Text *text, int lineno, int count)
  1158. {
  1159. TextMarker *marker;
  1160. for (marker=text->markers.first; marker; marker= marker->next)
  1161. if (marker->lineno>=lineno) {
  1162. marker->lineno+= count;
  1163. }
  1164. }
  1165. void txt_insert_buf(Text *text, const char *in_buffer)
  1166. {
  1167. int l=0, u, len, lineno= -1, count= 0;
  1168. size_t i=0, j;
  1169. TextLine *add;
  1170. char *buffer;
  1171. if (!text) return;
  1172. if (!in_buffer) return;
  1173. txt_delete_sel(text);
  1174. len= strlen(in_buffer);
  1175. buffer= BLI_strdupn(in_buffer, len);
  1176. len+= txt_extended_ascii_as_utf8(&buffer);
  1177. if (!undoing) txt_undo_add_block(text, UNDO_IBLOCK, buffer);
  1178. u= undoing;
  1179. undoing= 1;
  1180. /* Read the first line (or as close as possible */
  1181. while (buffer[i] && buffer[i]!='\n')
  1182. txt_add_raw_char(text, BLI_str_utf8_as_unicode_step(buffer, &i));
  1183. if (buffer[i]=='\n') txt_split_curline(text);
  1184. else { undoing = u; MEM_freeN(buffer); return; }
  1185. i++;
  1186. /* Read as many full lines as we can */
  1187. lineno= txt_get_span(text->lines.first, text->curl);
  1188. while (i<len) {
  1189. l=0;
  1190. while (buffer[i] && buffer[i]!='\n') {
  1191. i++; l++;
  1192. }
  1193. if (buffer[i]=='\n') {
  1194. add= txt_new_linen(buffer +(i-l), l);
  1195. BLI_insertlinkbefore(&text->lines, text->curl, add);
  1196. i++;
  1197. count++;
  1198. }
  1199. else {
  1200. if (count) {
  1201. txt_shift_markers(text, lineno, count);
  1202. count= 0;
  1203. }
  1204. for (j= i-l; j<i && j<len; )
  1205. txt_add_raw_char(text, BLI_str_utf8_as_unicode_step(buffer, &j));
  1206. break;
  1207. }
  1208. }
  1209. MEM_freeN(buffer);
  1210. if (count) {
  1211. txt_shift_markers(text, lineno, count);
  1212. }
  1213. undoing= u;
  1214. }
  1215. /******************/
  1216. /* Undo functions */
  1217. /******************/
  1218. static int max_undo_test(Text *text, int x)
  1219. {
  1220. while (text->undo_pos+x >= text->undo_len) {
  1221. if (text->undo_len*2 > TXT_MAX_UNDO) {
  1222. /* XXX error("Undo limit reached, buffer cleared\n"); */
  1223. MEM_freeN(text->undo_buf);
  1224. init_undo_text(text);
  1225. return 0;
  1226. }
  1227. else {
  1228. void *tmp= text->undo_buf;
  1229. text->undo_buf= MEM_callocN(text->undo_len*2, "undo buf");
  1230. memcpy(text->undo_buf, tmp, text->undo_len);
  1231. text->undo_len*=2;
  1232. MEM_freeN(tmp);
  1233. }
  1234. }
  1235. return 1;
  1236. }
  1237. static void dump_buffer(Text *text)
  1238. {
  1239. int i= 0;
  1240. while (i++<text->undo_pos) printf("%d: %d %c\n", i, text->undo_buf[i], text->undo_buf[i]);
  1241. }
  1242. void txt_print_undo(Text *text)
  1243. {
  1244. int i= 0;
  1245. int op;
  1246. const char *ops;
  1247. int linep, charp;
  1248. dump_buffer(text);
  1249. printf ("---< Undo Buffer >---\n");
  1250. printf ("UndoPosition is %d\n", text->undo_pos);
  1251. while (i<=text->undo_pos) {
  1252. op= text->undo_buf[i];
  1253. if (op==UNDO_CLEFT) {
  1254. ops= "Cursor left";
  1255. }
  1256. else if (op==UNDO_CRIGHT) {
  1257. ops= "Cursor right";
  1258. }
  1259. else if (op==UNDO_CUP) {
  1260. ops= "Cursor up";
  1261. }
  1262. else if (op==UNDO_CDOWN) {
  1263. ops= "Cursor down";
  1264. }
  1265. else if (op==UNDO_SLEFT) {
  1266. ops= "Selection left";
  1267. }
  1268. else if (op==UNDO_SRIGHT) {
  1269. ops= "Selection right";
  1270. }
  1271. else if (op==UNDO_SUP) {
  1272. ops= "Selection up";
  1273. }
  1274. else if (op==UNDO_SDOWN) {
  1275. ops= "Selection down";
  1276. }
  1277. else if (op==UNDO_STO) {
  1278. ops= "Selection ";
  1279. }
  1280. else if (op==UNDO_CTO) {
  1281. ops= "Cursor ";
  1282. }
  1283. else if (op==UNDO_INSERT_1) {
  1284. ops= "Insert ascii ";
  1285. }
  1286. else if (op==UNDO_INSERT_2) {
  1287. ops= "Insert 2 bytes ";
  1288. }
  1289. else if (op==UNDO_INSERT_3) {
  1290. ops= "Insert 3 bytes ";
  1291. }
  1292. else if (op==UNDO_INSERT_4) {
  1293. ops= "Insert unicode ";
  1294. }
  1295. else if (op==UNDO_BS_1) {
  1296. ops= "Backspace for ascii ";
  1297. }
  1298. else if (op==UNDO_BS_2) {
  1299. ops= "Backspace for 2 bytes ";
  1300. }
  1301. else if (op==UNDO_BS_3) {
  1302. ops= "Backspace for 3 bytes ";
  1303. }
  1304. else if (op==UNDO_BS_4) {
  1305. ops= "Backspace for unicode ";
  1306. }
  1307. else if (op==UNDO_DEL_1) {
  1308. ops= "Delete ascii ";
  1309. }
  1310. else if (op==UNDO_DEL_2) {
  1311. ops= "Delete 2 bytes ";
  1312. }
  1313. else if (op==UNDO_DEL_3) {
  1314. ops= "Delete 3 bytes ";
  1315. }
  1316. else if (op==UNDO_DEL_4) {
  1317. ops= "Delete unicode ";
  1318. }
  1319. else if (op==UNDO_SWAP) {
  1320. ops= "Cursor swap";
  1321. }
  1322. else if (op==UNDO_DBLOCK) {
  1323. ops= "Delete text block";
  1324. }
  1325. else if (op==UNDO_IBLOCK) {
  1326. ops= "Insert text block";
  1327. }
  1328. else if (op==UNDO_INDENT) {
  1329. ops= "Indent ";
  1330. }
  1331. else if (op==UNDO_UNINDENT) {
  1332. ops= "Unindent ";
  1333. }
  1334. else if (op==UNDO_COMMENT) {
  1335. ops= "Comment ";
  1336. }
  1337. else if (op==UNDO_UNCOMMENT) {
  1338. ops= "Uncomment ";
  1339. }
  1340. else {
  1341. ops= "Unknown";
  1342. }
  1343. printf ("Op (%o) at %d = %s", op, i, ops);
  1344. if (op >= UNDO_INSERT_1 && op <= UNDO_DEL_4) {
  1345. i++;
  1346. printf (" - Char is ");
  1347. switch (op) {
  1348. case UNDO_INSERT_1: case UNDO_BS_1: case UNDO_DEL_1:
  1349. printf ("%c", text->undo_buf[i]);
  1350. i++;
  1351. break;
  1352. case UNDO_INSERT_2: case UNDO_BS_2: case UNDO_DEL_2:
  1353. printf ("%c%c", text->undo_buf[i], text->undo_buf[i+1]);
  1354. i+=2;
  1355. break;
  1356. case UNDO_INSERT_3: case UNDO_BS_3: case UNDO_DEL_3:
  1357. printf ("%c%c%c", text->undo_buf[i], text->undo_buf[i+1], text->undo_buf[i+2]);
  1358. i+=3;
  1359. break;
  1360. case UNDO_INSERT_4: case UNDO_BS_4: case UNDO_DEL_4: {
  1361. unsigned int uc;
  1362. char c[BLI_UTF8_MAX+1];
  1363. size_t c_len;
  1364. uc= text->undo_buf[i]; i++;
  1365. uc= uc+(text->undo_buf[i]<<8); i++;
  1366. uc= uc+(text->undo_buf[i]<<16); i++;
  1367. uc= uc+(text->undo_buf[i]<<24); i++;
  1368. c_len= BLI_str_utf8_from_unicode(uc, c);
  1369. c[c_len]= '\0';
  1370. puts(c);
  1371. }
  1372. }
  1373. }
  1374. else if (op==UNDO_STO || op==UNDO_CTO) {
  1375. i++;
  1376. charp= text->undo_buf[i]; i++;
  1377. charp= charp+(text->undo_buf[i]<<8); i++;
  1378. linep= text->undo_buf[i]; i++;
  1379. linep= linep+(text->undo_buf[i]<<8); i++;
  1380. linep= linep+(text->undo_buf[i]<<16); i++;
  1381. linep= linep+(text->undo_buf[i]<<24); i++;
  1382. printf ("to <%d, %d> ", linep, charp);
  1383. charp= text->undo_buf[i]; i++;
  1384. charp= charp+(text->undo_buf[i]<<8); i++;
  1385. linep= text->undo_buf[i]; i++;
  1386. linep= linep+(text->undo_buf[i]<<8); i++;
  1387. linep= linep+(text->undo_buf[i]<<16); i++;
  1388. linep= linep+(text->undo_buf[i]<<24); i++;
  1389. printf ("from <%d, %d>", linep, charp);
  1390. }
  1391. else if (op==UNDO_DBLOCK || op==UNDO_IBLOCK) {
  1392. i++;
  1393. linep= text->undo_buf[i]; i++;
  1394. linep= linep+(text->undo_buf[i]<<8); i++;
  1395. linep= linep+(text->undo_buf[i]<<16); i++;
  1396. linep= linep+(text->undo_buf[i]<<24); i++;
  1397. printf (" (length %d) <", linep);
  1398. while (linep>0) {
  1399. putchar(text->undo_buf[i]);
  1400. linep--; i++;
  1401. }
  1402. linep= text->undo_buf[i]; i++;
  1403. linep= linep+(text->undo_buf[i]<<8); i++;
  1404. linep= linep+(text->undo_buf[i]<<16); i++;
  1405. linep= linep+(text->undo_buf[i]<<24); i++;
  1406. printf ("> (%d)", linep);
  1407. }
  1408. else if (op==UNDO_INDENT || op==UNDO_UNINDENT) {
  1409. i++;
  1410. charp= text->undo_buf[i]; i++;
  1411. charp= charp+(text->undo_buf[i]<<8); i++;
  1412. linep= text->undo_buf[i]; i++;
  1413. linep= linep+(text->undo_buf[i]<<8); i++;
  1414. linep= linep+(text->undo_buf[i]<<16); i++;
  1415. linep= linep+(text->undo_buf[i]<<24); i++;
  1416. printf ("to <%d, %d> ", linep, charp);
  1417. charp= text->undo_buf[i]; i++;
  1418. charp= charp+(text->undo_buf[i]<<8); i++;
  1419. linep= text->undo_buf[i]; i++;
  1420. linep= linep+(text->undo_buf[i]<<8); i++;
  1421. linep= linep+(text->undo_buf[i]<<16); i++;
  1422. linep= linep+(text->undo_buf[i]<<24); i++;
  1423. printf ("from <%d, %d>", linep, charp);
  1424. }
  1425. printf (" %d\n", i);
  1426. i++;
  1427. }
  1428. }
  1429. static void txt_undo_add_op(Text *text, int op)
  1430. {
  1431. if (!max_undo_test(text, 2))
  1432. return;
  1433. text->undo_pos++;
  1434. text->undo_buf[text->undo_pos]= op;
  1435. text->undo_buf[text->undo_pos+1]= 0;
  1436. }
  1437. static void txt_undo_store_uint16(char *undo_buf, int *undo_pos, unsigned short value)
  1438. {
  1439. undo_buf[*undo_pos]= (value)&0xff;
  1440. (*undo_pos)++;
  1441. undo_buf[*undo_pos]= (value>>8)&0xff;
  1442. (*undo_pos)++;
  1443. }
  1444. static void txt_undo_store_uint32(char *undo_buf, int *undo_pos, unsigned int value)
  1445. {
  1446. undo_buf[*undo_pos]= (value)&0xff;
  1447. (*undo_pos)++;
  1448. undo_buf[*undo_pos]= (value>>8)&0xff;
  1449. (*undo_pos)++;
  1450. undo_buf[*undo_pos]= (value>>16)&0xff;
  1451. (*undo_pos)++;
  1452. undo_buf[*undo_pos]= (value>>24)&0xff;
  1453. (*undo_pos)++;
  1454. }
  1455. static void txt_undo_add_block(Text *text, int op, const char *buf)
  1456. {
  1457. unsigned int length= strlen(buf);
  1458. if (!max_undo_test(text, length+11))
  1459. return;
  1460. text->undo_pos++;
  1461. text->undo_buf[text->undo_pos]= op;
  1462. text->undo_pos++;
  1463. txt_undo_store_uint32(text->undo_buf, &text->undo_pos, length);
  1464. strncpy(text->undo_buf+text->undo_pos, buf, length);
  1465. text->undo_pos+=length;
  1466. txt_undo_store_uint32(text->undo_buf, &text->undo_pos, length);
  1467. text->undo_buf[text->undo_pos]= op;
  1468. text->undo_buf[text->undo_pos+1]= 0;
  1469. }
  1470. void txt_undo_add_toop(Text *text, int op, unsigned int froml, unsigned short fromc, unsigned int tol, unsigned short toc)
  1471. {
  1472. if (!max_undo_test(text, 15))
  1473. return;
  1474. if (froml==tol && fromc==toc) return;
  1475. text->undo_pos++;
  1476. text->undo_buf[text->undo_pos]= op;
  1477. text->undo_pos++;
  1478. txt_undo_store_uint16(text->undo_buf, &text->undo_pos, fromc);
  1479. txt_undo_store_uint32(text->undo_buf, &text->undo_pos, froml);
  1480. txt_undo_store_uint16(text->undo_buf, &text->undo_pos, toc);
  1481. txt_undo_store_uint32(text->undo_buf, &text->undo_pos, tol);
  1482. text->undo_buf[text->undo_pos]= op;
  1483. text->undo_buf[text->undo_pos+1]= 0;
  1484. }
  1485. static void txt_undo_add_charop(Text *text, int op_start, unsigned int c)
  1486. {
  1487. char utf8[BLI_UTF8_MAX];
  1488. size_t i, utf8_size = BLI_str_utf8_from_unicode(c, utf8);
  1489. if (!max_undo_test(text, 3 + utf8_size))
  1490. return;
  1491. text->undo_pos++;
  1492. if (utf8_size < 4) {
  1493. text->undo_buf[text->undo_pos]= op_start + utf8_size - 1;
  1494. text->undo_pos++;
  1495. for (i = 0; i < utf8_size; i++) {
  1496. text->undo_buf[text->undo_pos]= utf8[i];
  1497. text->undo_pos++;
  1498. }
  1499. text->undo_buf[text->undo_pos]= op_start + utf8_size - 1;
  1500. }
  1501. else {
  1502. text->undo_buf[text->undo_pos]= op_start + 3;
  1503. text->undo_pos++;
  1504. txt_undo_store_uint32(text->undo_buf, &text->undo_pos, c);
  1505. text->undo_buf[text->undo_pos]= op_start + 3;
  1506. }
  1507. text->undo_buf[text->undo_pos+1]= 0;
  1508. }
  1509. static unsigned short txt_undo_read_uint16(const char *undo_buf, int *undo_pos)
  1510. {
  1511. unsigned short val;
  1512. val= undo_buf[*undo_pos]; (*undo_pos)--;
  1513. val= (val<<8)+undo_buf[*undo_pos]; (*undo_pos)--;
  1514. return val;
  1515. }
  1516. static unsigned int txt_undo_read_uint32(const char *undo_buf, int *undo_pos)
  1517. {
  1518. unsigned int val;
  1519. val= undo_buf[*undo_pos]; (*undo_pos)--;
  1520. val= (val<<8)+undo_buf[*undo_pos]; (*undo_pos)--;
  1521. val= (val<<8)+undo_buf[*undo_pos]; (*undo_pos)--;
  1522. val= (val<<8)+undo_buf[*undo_pos]; (*undo_pos)--;
  1523. return val;
  1524. }
  1525. static unsigned int txt_undo_read_unicode(const char *undo_buf, int *undo_pos, short bytes)
  1526. {
  1527. unsigned int unicode;
  1528. char utf8[BLI_UTF8_MAX+1];
  1529. switch (bytes) {
  1530. case 1: /* ascii */
  1531. unicode = undo_buf[*undo_pos]; (*undo_pos)--;
  1532. break;
  1533. case 2: /* 2-byte symbol */
  1534. utf8[2] = '\0';
  1535. utf8[1] = undo_buf[*undo_pos]; (*undo_pos)--;
  1536. utf8[0] = undo_buf[*undo_pos]; (*undo_pos)--;
  1537. unicode= BLI_str_utf8_as_unicode(utf8);
  1538. break;
  1539. case 3: /* 3-byte symbol */
  1540. utf8[3] = '\0';
  1541. utf8[2] = undo_buf[*undo_pos]; (*undo_pos)--;
  1542. utf8[1] = undo_buf[*undo_pos]; (*undo_pos)--;
  1543. utf8[0] = undo_buf[*undo_pos]; (*undo_pos)--;
  1544. unicode= BLI_str_utf8_as_unicode(utf8);
  1545. break;
  1546. case 4: /* 32-bit unicode symbol */
  1547. unicode= txt_undo_read_uint32(undo_buf, undo_pos);
  1548. default:
  1549. /* should never happen */
  1550. BLI_assert(0);
  1551. unicode= 0;
  1552. }
  1553. return unicode;
  1554. }
  1555. static unsigned short txt_redo_read_uint16(const char *undo_buf, int *undo_pos)
  1556. {
  1557. unsigned short val;
  1558. val = undo_buf[*undo_pos]; (*undo_pos)++;
  1559. val = val+(undo_buf[*undo_pos]<<8); (*undo_pos)++;
  1560. return val;
  1561. }
  1562. static unsigned int txt_redo_read_uint32(const char *undo_buf, int *undo_pos)
  1563. {
  1564. unsigned int val;
  1565. val= undo_buf[*undo_pos]; (*undo_pos)++;
  1566. val= val+(undo_buf[*undo_pos]<<8); (*undo_pos)++;
  1567. val= val+(undo_buf[*undo_pos]<<16); (*undo_pos)++;
  1568. val= val+(undo_buf[*undo_pos]<<24); (*undo_pos)++;
  1569. return val;
  1570. }
  1571. static unsigned int txt_redo_read_unicode(const char *undo_buf, int *undo_pos, short bytes)
  1572. {
  1573. unsigned int unicode;
  1574. char utf8[BLI_UTF8_MAX+1];
  1575. switch (bytes) {
  1576. case 1: /* ascii */
  1577. unicode = undo_buf[*undo_pos]; (*undo_pos)++;
  1578. break;
  1579. case 2: /* 2-byte symbol */
  1580. utf8[0] = undo_buf[*undo_pos]; (*undo_pos)++;
  1581. utf8[1] = undo_buf[*undo_pos]; (*undo_pos)++;
  1582. utf8[2] = '\0';
  1583. unicode= BLI_str_utf8_as_unicode(utf8);
  1584. break;
  1585. case 3: /* 3-byte symbol */
  1586. utf8[0] = undo_buf[*undo_pos]; (*undo_pos)++;
  1587. utf8[1] = undo_buf[*undo_pos]; (*undo_pos)++;
  1588. utf8[2] = undo_buf[*undo_pos]; (*undo_pos)++;
  1589. utf8[3] = '\0';
  1590. unicode= BLI_str_utf8_as_unicode(utf8);
  1591. break;
  1592. case 4: /* 32-bit unicode symbol */
  1593. unicode= txt_undo_read_uint32(undo_buf, undo_pos);
  1594. default:
  1595. /* should never happen */
  1596. BLI_assert(0);
  1597. unicode= 0;
  1598. }
  1599. return unicode;
  1600. }
  1601. void txt_do_undo(Text *text)
  1602. {
  1603. int op= text->undo_buf[text->undo_pos];
  1604. unsigned int linep, i;
  1605. unsigned short charp;
  1606. TextLine *holdl;
  1607. int holdc, holdln;
  1608. char *buf;
  1609. if (text->undo_pos<0) {
  1610. return;
  1611. }
  1612. text->undo_pos--;
  1613. undoing= 1;
  1614. switch(op) {
  1615. case UNDO_CLEFT:
  1616. txt_move_right(text, 0);
  1617. break;
  1618. case UNDO_CRIGHT:
  1619. txt_move_left(text, 0);
  1620. break;
  1621. case UNDO_CUP:
  1622. txt_move_down(text, 0);
  1623. break;
  1624. case UNDO_CDOWN:
  1625. txt_move_up(text, 0);
  1626. break;
  1627. case UNDO_SLEFT:
  1628. txt_move_right(text, 1);
  1629. break;
  1630. case UNDO_SRIGHT:
  1631. txt_move_left(text, 1);
  1632. break;
  1633. case UNDO_SUP:
  1634. txt_move_down(text, 1);
  1635. break;
  1636. case UNDO_SDOWN:
  1637. txt_move_up(text, 1);
  1638. break;
  1639. case UNDO_CTO:
  1640. case UNDO_STO:
  1641. text->undo_pos--;
  1642. text->undo_pos--;
  1643. text->undo_pos--;
  1644. text->undo_pos--;
  1645. text->undo_pos--;
  1646. text->undo_pos--;
  1647. linep= txt_undo_read_uint32(text->undo_buf, &text->undo_pos);
  1648. charp= txt_undo_read_uint16(text->undo_buf, &text->undo_pos);
  1649. if (op==UNDO_CTO) {
  1650. txt_move_toline(text, linep, 0);
  1651. text->curc= charp;
  1652. txt_pop_sel(text);
  1653. }
  1654. else {
  1655. txt_move_toline(text, linep, 1);
  1656. text->selc= charp;
  1657. }
  1658. text->undo_pos--;
  1659. break;
  1660. case UNDO_INSERT_1: case UNDO_INSERT_2: case UNDO_INSERT_3: case UNDO_INSERT_4:
  1661. txt_backspace_char(text);
  1662. text->undo_pos-= op - UNDO_INSERT_1 + 1;
  1663. text->undo_pos--;
  1664. break;
  1665. case UNDO_BS_1: case UNDO_BS_2: case UNDO_BS_3: case UNDO_BS_4:
  1666. charp = op - UNDO_BS_1 + 1;
  1667. txt_add_char(text, txt_undo_read_unicode(text->undo_buf, &text->undo_pos, charp));
  1668. text->undo_pos--;
  1669. break;
  1670. case UNDO_DEL_1: case UNDO_DEL_2: case UNDO_DEL_3: case UNDO_DEL_4:
  1671. charp = op - UNDO_DEL_1 + 1;
  1672. txt_add_char(text, txt_undo_read_unicode(text->undo_buf, &text->undo_pos, charp));
  1673. txt_move_left(text, 0);
  1674. text->undo_pos--;
  1675. break;
  1676. case UNDO_SWAP:
  1677. txt_curs_swap(text);
  1678. break;
  1679. case UNDO_DBLOCK:
  1680. linep= txt_undo_read_uint32(text->undo_buf, &text->undo_pos);
  1681. buf= MEM_mallocN(linep+1, "dblock buffer");
  1682. for (i=0; i < linep; i++) {
  1683. buf[(linep-1)-i]= text->undo_buf[text->undo_pos];
  1684. text->undo_pos--;
  1685. }
  1686. buf[i]= 0;
  1687. txt_curs_first(text, &holdl, &holdc);
  1688. holdln= txt_get_span(text->lines.first, holdl);
  1689. txt_insert_buf(text, buf);
  1690. MEM_freeN(buf);
  1691. text->curl= text->lines.first;
  1692. while (holdln>0) {
  1693. if (text->curl->next)
  1694. text->curl= text->curl->next;
  1695. holdln--;
  1696. }
  1697. text->curc= holdc;
  1698. text->undo_pos--;
  1699. text->undo_pos--;
  1700. text->undo_pos--;
  1701. text->undo_pos--;
  1702. text->undo_pos--;
  1703. break;
  1704. case UNDO_IBLOCK:
  1705. linep= txt_undo_read_uint32(text->undo_buf, &text->undo_pos);
  1706. txt_delete_sel(text);
  1707. /* txt_backspace_char removes utf8-characters, not bytes */
  1708. buf= MEM_mallocN(linep+1, "iblock buffer");
  1709. for (i=0; i < linep; i++) {
  1710. buf[(linep-1)-i]= text->undo_buf[text->undo_pos];
  1711. text->undo_pos--;
  1712. }
  1713. buf[i]= 0;
  1714. linep= txt_utf8_len(buf);
  1715. MEM_freeN(buf);
  1716. while (linep>0) {
  1717. txt_backspace_char(text);
  1718. linep--;
  1719. }
  1720. text->undo_pos--;
  1721. text->undo_pos--;
  1722. text->undo_pos--;
  1723. text->undo_pos--;
  1724. text->undo_pos--;
  1725. break;
  1726. case UNDO_INDENT:
  1727. case UNDO_UNINDENT:
  1728. case UNDO_COMMENT:
  1729. case UNDO_UNCOMMENT:
  1730. linep= txt_undo_read_uint32(text->undo_buf, &text->undo_pos);
  1731. //linep is now the end line of the selection
  1732. charp = txt_undo_read_uint16(text->undo_buf, &text->undo_pos);
  1733. //charp is the last char selected or text->line->len
  1734. //set the selection for this now
  1735. text->selc = charp;
  1736. text->sell = text->lines.first;
  1737. for (i= 0; i < linep; i++) {
  1738. text->sell = text->sell->next;
  1739. }
  1740. linep= txt_undo_read_uint32(text->undo_buf, &text->undo_pos);
  1741. //first line to be selected
  1742. charp = txt_undo_read_uint16(text->undo_buf, &text->undo_pos);
  1743. //first postion to be selected
  1744. text->curc = charp;
  1745. text->curl = text->lines.first;
  1746. for (i = 0; i < linep; i++) {
  1747. text->curl = text->curl->next;
  1748. }
  1749. if (op==UNDO_INDENT) {
  1750. txt_unindent(text);
  1751. }
  1752. else if (op== UNDO_UNINDENT) {
  1753. txt_indent(text);
  1754. }
  1755. else if (op == UNDO_COMMENT) {
  1756. txt_uncomment(text);
  1757. }
  1758. else if (op == UNDO_UNCOMMENT) {
  1759. txt_comment(text);
  1760. }
  1761. text->undo_pos--;
  1762. break;
  1763. default:
  1764. //XXX error("Undo buffer error - resetting");
  1765. text->undo_pos= -1;
  1766. break;
  1767. }
  1768. /* next undo step may need evaluating */
  1769. if (text->undo_pos>=0) {
  1770. switch (text->undo_buf[text->undo_pos]) {
  1771. case UNDO_STO:
  1772. txt_do_undo(text);
  1773. txt_do_redo(text); /* selections need restoring */
  1774. break;
  1775. case UNDO_SWAP:
  1776. txt_do_undo(text); /* swaps should appear transparent */
  1777. break;
  1778. }
  1779. }
  1780. undoing= 0;
  1781. }
  1782. void txt_do_redo(Text *text)
  1783. {
  1784. char op;
  1785. unsigned int linep, i;
  1786. unsigned short charp;
  1787. char *buf;
  1788. text->undo_pos++;
  1789. op= text->undo_buf[text->undo_pos];
  1790. if (!op) {
  1791. text->undo_pos--;
  1792. return;
  1793. }
  1794. undoing= 1;
  1795. switch(op) {
  1796. case UNDO_CLEFT:
  1797. txt_move_left(text, 0);
  1798. break;
  1799. case UNDO_CRIGHT:
  1800. txt_move_right(text, 0);
  1801. break;
  1802. case UNDO_CUP:
  1803. txt_move_up(text, 0);
  1804. break;
  1805. case UNDO_CDOWN:
  1806. txt_move_down(text, 0);
  1807. break;
  1808. case UNDO_SLEFT:
  1809. txt_move_left(text, 1);
  1810. break;
  1811. case UNDO_SRIGHT:
  1812. txt_move_right(text, 1);
  1813. break;
  1814. case UNDO_SUP:
  1815. txt_move_up(text, 1);
  1816. break;
  1817. case UNDO_SDOWN:
  1818. txt_move_down(text, 1);
  1819. break;
  1820. case UNDO_INSERT_1: case UNDO_INSERT_2: case UNDO_INSERT_3: case UNDO_INSERT_4:
  1821. text->undo_pos++;
  1822. charp = op - UNDO_INSERT_1 + 1;
  1823. txt_add_char(text, txt_redo_read_unicode(text->undo_buf, &text->undo_pos, charp));
  1824. break;
  1825. case UNDO_BS_1: case UNDO_BS_2: case UNDO_BS_3: case UNDO_BS_4:
  1826. text->undo_pos++;
  1827. txt_backspace_char(text);
  1828. text->undo_pos+= op - UNDO_BS_1 + 1;
  1829. break;
  1830. case UNDO_DEL_1: case UNDO_DEL_2: case UNDO_DEL_3: case UNDO_DEL_4:
  1831. text->undo_pos++;
  1832. txt_delete_char(text);
  1833. text->undo_pos+= op - UNDO_DEL_1 + 1;
  1834. break;
  1835. case UNDO_SWAP:
  1836. txt_curs_swap(text);
  1837. txt_do_redo(text); /* swaps should appear transparent a*/
  1838. break;
  1839. case UNDO_CTO:
  1840. case UNDO_STO:
  1841. text->undo_pos++;
  1842. text->undo_pos++;
  1843. text->undo_pos++;
  1844. text->undo_pos++;
  1845. text->undo_pos++;
  1846. text->undo_pos++;
  1847. text->undo_pos++;
  1848. charp= txt_redo_read_uint16(text->undo_buf, &text->undo_pos);
  1849. linep= txt_redo_read_uint32(text->undo_buf, &text->undo_pos);
  1850. if (op==UNDO_CTO) {
  1851. txt_move_toline(text, linep, 0);
  1852. text->curc= charp;
  1853. txt_pop_sel(text);
  1854. }
  1855. else {
  1856. txt_move_toline(text, linep, 1);
  1857. text->selc= charp;
  1858. }
  1859. break;
  1860. case UNDO_DBLOCK:
  1861. text->undo_pos++;
  1862. linep= txt_redo_read_uint32(text->undo_buf, &text->undo_pos);
  1863. txt_delete_sel(text);
  1864. text->undo_pos+=linep;
  1865. text->undo_pos++;
  1866. text->undo_pos++;
  1867. text->undo_pos++;
  1868. text->undo_pos++;
  1869. break;
  1870. case UNDO_IBLOCK:
  1871. text->undo_pos++;
  1872. linep= txt_redo_read_uint32(text->undo_buf, &text->undo_pos);
  1873. buf= MEM_mallocN(linep+1, "iblock buffer");
  1874. memcpy (buf, &text->undo_buf[text->undo_pos], linep);
  1875. text->undo_pos+= linep;
  1876. buf[linep]= 0;
  1877. txt_insert_buf(text, buf);
  1878. MEM_freeN(buf);
  1879. text->undo_pos++;
  1880. text->undo_pos++;
  1881. text->undo_pos++;
  1882. text->undo_pos++;
  1883. break;
  1884. case UNDO_INDENT:
  1885. case UNDO_UNINDENT:
  1886. case UNDO_COMMENT:
  1887. case UNDO_UNCOMMENT:
  1888. text->undo_pos++;
  1889. charp = txt_redo_read_uint16(text->undo_buf, &text->undo_pos);
  1890. //charp is the first char selected or 0
  1891. linep= txt_redo_read_uint32(text->undo_buf, &text->undo_pos);
  1892. //linep is now the first line of the selection
  1893. //set the selcetion for this now
  1894. text->curc = charp;
  1895. text->curl = text->lines.first;
  1896. for (i= 0; i < linep; i++) {
  1897. text->curl = text->curl->next;
  1898. }
  1899. charp = txt_redo_read_uint16(text->undo_buf, &text->undo_pos);
  1900. //last postion to be selected
  1901. linep= txt_redo_read_uint32(text->undo_buf, &text->undo_pos);
  1902. //Last line to be selected
  1903. text->selc = charp;
  1904. text->sell = text->lines.first;
  1905. for (i = 0; i < linep; i++) {
  1906. text->sell = text->sell->next;
  1907. }
  1908. if (op==UNDO_INDENT) {
  1909. txt_indent(text);
  1910. }
  1911. else if (op== UNDO_UNINDENT) {
  1912. txt_unindent(text);
  1913. }
  1914. else if (op == UNDO_COMMENT) {
  1915. txt_comment(text);
  1916. }
  1917. else if (op == UNDO_UNCOMMENT) {
  1918. txt_uncomment(text);
  1919. }
  1920. break;
  1921. default:
  1922. //XXX error("Undo buffer error - resetting");
  1923. text->undo_pos= -1;
  1924. break;
  1925. }
  1926. undoing= 0;
  1927. }
  1928. /**************************/
  1929. /* Line editing functions */
  1930. /**************************/
  1931. void txt_split_curline (Text *text)
  1932. {
  1933. TextLine *ins;
  1934. TextMarker *mrk;
  1935. char *left, *right;
  1936. int lineno= -1;
  1937. if (!text) return;
  1938. if (!text->curl) return;
  1939. txt_delete_sel(text);
  1940. /* Move markers */
  1941. lineno= txt_get_span(text->lines.first, text->curl);
  1942. mrk= text->markers.first;
  1943. while (mrk) {
  1944. if (mrk->lineno==lineno && mrk->start>text->curc) {
  1945. mrk->lineno++;
  1946. mrk->start -= text->curc;
  1947. mrk->end -= text->curc;
  1948. }
  1949. else if (mrk->lineno > lineno) {
  1950. mrk->lineno++;
  1951. }
  1952. mrk= mrk->next;
  1953. }
  1954. /* Make the two half strings */
  1955. left= MEM_mallocN(text->curc+1, "textline_string");
  1956. if (text->curc) memcpy(left, text->curl->line, text->curc);
  1957. left[text->curc]=0;
  1958. right= MEM_mallocN(text->curl->len - text->curc+1, "textline_string");
  1959. memcpy(right, text->curl->line+text->curc, text->curl->len-text->curc+1);
  1960. MEM_freeN(text->curl->line);
  1961. if (text->curl->format) MEM_freeN(text->curl->format);
  1962. /* Make the new TextLine */
  1963. ins= MEM_mallocN(sizeof(TextLine), "textline");
  1964. ins->line= left;
  1965. ins->format= NULL;
  1966. ins->len= text->curc;
  1967. text->curl->line= right;
  1968. text->curl->format= NULL;
  1969. text->curl->len= text->curl->len - text->curc;
  1970. BLI_insertlinkbefore(&text->lines, text->curl, ins);
  1971. text->curc=0;
  1972. txt_make_dirty(text);
  1973. txt_clean_text(text);
  1974. txt_pop_sel(text);
  1975. if (!undoing) txt_undo_add_charop(text, UNDO_INSERT_1, '\n');
  1976. }
  1977. static void txt_delete_line (Text *text, TextLine *line)
  1978. {
  1979. TextMarker *mrk=NULL, *nxt;
  1980. int lineno= -1;
  1981. if (!text) return;
  1982. if (!text->curl) return;
  1983. lineno= txt_get_span(text->lines.first, line);
  1984. mrk= text->markers.first;
  1985. while (mrk) {
  1986. nxt= mrk->next;
  1987. if (mrk->lineno==lineno)
  1988. BLI_freelinkN(&text->markers, mrk);
  1989. else if (mrk->lineno > lineno)
  1990. mrk->lineno--;
  1991. mrk= nxt;
  1992. }
  1993. BLI_remlink (&text->lines, line);
  1994. if (line->line) MEM_freeN(line->line);
  1995. if (line->format) MEM_freeN(line->format);
  1996. MEM_freeN(line);
  1997. txt_make_dirty(text);
  1998. txt_clean_text(text);
  1999. }
  2000. static void txt_combine_lines (Text *text, TextLine *linea, TextLine *lineb)
  2001. {
  2002. char *tmp;
  2003. TextMarker *mrk= NULL;
  2004. int lineno=-1;
  2005. if (!text) return;
  2006. if (!linea || !lineb) return;
  2007. mrk= txt_find_marker_region(text, lineb, 0, lineb->len, 0, 0);
  2008. if (mrk) {
  2009. lineno= mrk->lineno;
  2010. do {
  2011. mrk->lineno--;
  2012. mrk->start += linea->len;
  2013. mrk->end += linea->len;
  2014. mrk= mrk->next;
  2015. } while (mrk && mrk->lineno==lineno);
  2016. }
  2017. if (lineno==-1) lineno= txt_get_span(text->lines.first, lineb);
  2018. tmp= MEM_mallocN(linea->len+lineb->len+1, "textline_string");
  2019. strcpy(tmp, linea->line);
  2020. strcat(tmp, lineb->line);
  2021. make_new_line(linea, tmp);
  2022. txt_delete_line(text, lineb);
  2023. txt_make_dirty(text);
  2024. txt_clean_text(text);
  2025. }
  2026. void txt_delete_char(Text *text)
  2027. {
  2028. unsigned int c='\n';
  2029. if (!text) return;
  2030. if (!text->curl) return;
  2031. if (txt_has_sel(text)) { /* deleting a selection */
  2032. txt_delete_sel(text);
  2033. txt_make_dirty(text);
  2034. return;
  2035. }
  2036. else if (text->curc== text->curl->len) { /* Appending two lines */
  2037. if (text->curl->next) {
  2038. txt_combine_lines(text, text->curl, text->curl->next);
  2039. txt_pop_sel(text);
  2040. }
  2041. else
  2042. return;
  2043. }
  2044. else { /* Just deleting a char */
  2045. size_t c_len = 0;
  2046. TextMarker *mrk;
  2047. c= BLI_str_utf8_as_unicode_and_size(text->curl->line + text->curc, &c_len);
  2048. mrk= txt_find_marker_region(text, text->curl, text->curc - c_len, text->curl->len, 0, 0);
  2049. if (mrk) {
  2050. int lineno= mrk->lineno;
  2051. if (mrk->end==text->curc) {
  2052. if ((mrk->flags & TMARK_TEMP) && !(mrk->flags & TMARK_EDITALL)) {
  2053. txt_clear_markers(text, mrk->group, TMARK_TEMP);
  2054. }
  2055. else {
  2056. BLI_freelinkN(&text->markers, mrk);
  2057. }
  2058. return;
  2059. }
  2060. do {
  2061. if (mrk->start>text->curc) mrk->start-= c_len;
  2062. mrk->end-= c_len;
  2063. mrk= mrk->next;
  2064. } while (mrk && mrk->lineno==lineno);
  2065. }
  2066. memmove(text->curl->line+text->curc, text->curl->line+text->curc+c_len, text->curl->len-text->curc-c_len+1);
  2067. text->curl->len-= c_len;
  2068. txt_pop_sel(text);
  2069. }
  2070. txt_make_dirty(text);
  2071. txt_clean_text(text);
  2072. if (!undoing) txt_undo_add_charop(text, UNDO_DEL_1, c);
  2073. }
  2074. void txt_delete_word (Text *text)
  2075. {
  2076. txt_jump_right(text, 1);
  2077. txt_delete_sel(text);
  2078. }
  2079. void txt_backspace_char (Text *text)
  2080. {
  2081. unsigned int c='\n';
  2082. if (!text) return;
  2083. if (!text->curl) return;
  2084. if (txt_has_sel(text)) { /* deleting a selection */
  2085. txt_delete_sel(text);
  2086. txt_make_dirty(text);
  2087. return;
  2088. }
  2089. else if (text->curc==0) { /* Appending two lines */
  2090. if (!text->curl->prev) return;
  2091. text->curl= text->curl->prev;
  2092. text->curc= text->curl->len;
  2093. txt_combine_lines(text, text->curl, text->curl->next);
  2094. txt_pop_sel(text);
  2095. }
  2096. else { /* Just backspacing a char */
  2097. size_t c_len = 0;
  2098. TextMarker *mrk;
  2099. char *prev = BLI_str_prev_char_utf8(text->curl->line + text->curc);
  2100. c= BLI_str_utf8_as_unicode_and_size(prev, &c_len);
  2101. mrk= txt_find_marker_region(text, text->curl, text->curc - c_len, text->curl->len, 0, 0);
  2102. if (mrk) {
  2103. int lineno= mrk->lineno;
  2104. if (mrk->start==text->curc) {
  2105. if ((mrk->flags & TMARK_TEMP) && !(mrk->flags & TMARK_EDITALL)) {
  2106. txt_clear_markers(text, mrk->group, TMARK_TEMP);
  2107. }
  2108. else {
  2109. BLI_freelinkN(&text->markers, mrk);
  2110. }
  2111. return;
  2112. }
  2113. do {
  2114. if (mrk->start>text->curc - c_len) mrk->start-= c_len;
  2115. mrk->end-= c_len;
  2116. mrk= mrk->next;
  2117. } while (mrk && mrk->lineno==lineno);
  2118. }
  2119. /* source and destination overlap, don't use memcpy() */
  2120. memmove(text->curl->line + text->curc - c_len,
  2121. text->curl->line + text->curc,
  2122. text->curl->len - text->curc + 1);
  2123. text->curl->len-= c_len;
  2124. text->curc-= c_len;
  2125. txt_pop_sel(text);
  2126. }
  2127. txt_make_dirty(text);
  2128. txt_clean_text(text);
  2129. if (!undoing) txt_undo_add_charop(text, UNDO_BS_1, c);
  2130. }
  2131. void txt_backspace_word (Text *text)
  2132. {
  2133. txt_jump_left(text, 1);
  2134. txt_delete_sel(text);
  2135. }
  2136. /* Max spaces to replace a tab with, currently hardcoded to TXT_TABSIZE = 4.
  2137. * Used by txt_convert_tab_to_spaces, indent and unindent.
  2138. * Remember to change this string according to max tab size */
  2139. static char tab_to_spaces[] = " ";
  2140. static void txt_convert_tab_to_spaces (Text *text)
  2141. {
  2142. /* sb aims to pad adjust the tab-width needed so that the right number of spaces
  2143. * is added so that the indention of the line is the right width (i.e. aligned
  2144. * to multiples of TXT_TABSIZE)
  2145. */
  2146. char *sb = &tab_to_spaces[text->curc % TXT_TABSIZE];
  2147. txt_insert_buf(text, sb);
  2148. }
  2149. static int txt_add_char_intern (Text *text, unsigned int add, int replace_tabs)
  2150. {
  2151. int lineno;
  2152. char *tmp, ch[BLI_UTF8_MAX];
  2153. TextMarker *mrk;
  2154. size_t add_len;
  2155. if (!text) return 0;
  2156. if (!text->curl) return 0;
  2157. if (add=='\n') {
  2158. txt_split_curline(text);
  2159. return 1;
  2160. }
  2161. /* insert spaces rather than tabs */
  2162. if (add == '\t' && replace_tabs) {
  2163. txt_convert_tab_to_spaces(text);
  2164. return 1;
  2165. }
  2166. txt_delete_sel(text);
  2167. add_len = BLI_str_utf8_from_unicode(add, ch);
  2168. mrk= txt_find_marker_region(text, text->curl, text->curc-1, text->curl->len, 0, 0);
  2169. if (mrk) {
  2170. lineno= mrk->lineno;
  2171. do {
  2172. if (mrk->start>text->curc) mrk->start+= add_len;
  2173. mrk->end+= add_len;
  2174. mrk= mrk->next;
  2175. } while (mrk && mrk->lineno==lineno);
  2176. }
  2177. tmp= MEM_mallocN(text->curl->len+add_len+1, "textline_string");
  2178. memcpy(tmp, text->curl->line, text->curc);
  2179. memcpy(tmp+text->curc, ch, add_len);
  2180. memcpy(tmp+text->curc+add_len, text->curl->line+text->curc, text->curl->len-text->curc+1);
  2181. make_new_line(text->curl, tmp);
  2182. text->curc+= add_len;
  2183. txt_pop_sel(text);
  2184. txt_make_dirty(text);
  2185. txt_clean_text(text);
  2186. if (!undoing) txt_undo_add_charop(text, UNDO_INSERT_1, add);
  2187. return 1;
  2188. }
  2189. int txt_add_char (Text *text, unsigned int add)
  2190. {
  2191. return txt_add_char_intern(text, add, text->flags & TXT_TABSTOSPACES);
  2192. }
  2193. int txt_add_raw_char (Text *text, unsigned int add)
  2194. {
  2195. return txt_add_char_intern(text, add, 0);
  2196. }
  2197. void txt_delete_selected(Text *text)
  2198. {
  2199. txt_delete_sel(text);
  2200. txt_make_dirty(text);
  2201. }
  2202. int txt_replace_char (Text *text, unsigned int add)
  2203. {
  2204. unsigned int del;
  2205. size_t del_size = 0, add_size;
  2206. char ch[BLI_UTF8_MAX];
  2207. if (!text) return 0;
  2208. if (!text->curl) return 0;
  2209. /* If text is selected or we're at the end of the line just use txt_add_char */
  2210. if (text->curc==text->curl->len || txt_has_sel(text) || add=='\n') {
  2211. int i= txt_add_char(text, add);
  2212. TextMarker *mrk= txt_find_marker(text, text->curl, text->curc, 0, 0);
  2213. if (mrk) BLI_freelinkN(&text->markers, mrk);
  2214. return i;
  2215. }
  2216. del= BLI_str_utf8_as_unicode_and_size(text->curl->line + text->curc, &del_size);
  2217. add_size= BLI_str_utf8_from_unicode(add, ch);
  2218. if (add_size > del_size) {
  2219. char *tmp= MEM_mallocN(text->curl->len+add_size-del_size+1, "textline_string");
  2220. memcpy(tmp, text->curl->line, text->curc);
  2221. memcpy(tmp+text->curc+add_size, text->curl->line+text->curc+del_size, text->curl->len-text->curc-del_size+1);
  2222. MEM_freeN(text->curl->line);
  2223. text->curl->line = tmp;
  2224. }
  2225. else if (add_size < del_size) {
  2226. char *tmp= text->curl->line;
  2227. memmove(tmp+text->curc+add_size, tmp+text->curc+del_size, text->curl->len-text->curc-del_size+1);
  2228. }
  2229. memcpy(text->curl->line + text->curc, ch, add_size);
  2230. text->curc+= add_size;
  2231. txt_pop_sel(text);
  2232. txt_make_dirty(text);
  2233. txt_clean_text(text);
  2234. /* Should probably create a new op for this */
  2235. if (!undoing) {
  2236. txt_undo_add_charop(text, UNDO_DEL_1, del);
  2237. txt_undo_add_charop(text, UNDO_INSERT_1, add);
  2238. }
  2239. return 1;
  2240. }
  2241. void txt_indent(Text *text)
  2242. {
  2243. int len, num;
  2244. char *tmp;
  2245. const char *add = "\t";
  2246. int indentlen = 1;
  2247. /* hardcoded: TXT_TABSIZE = 4 spaces: */
  2248. int spaceslen = TXT_TABSIZE;
  2249. if (ELEM3(NULL, text, text->curl, text->sell)) {
  2250. return;
  2251. }
  2252. if (!text) return;
  2253. if (!text->curl) return;
  2254. if (!text->sell) return;
  2255. /* insert spaces rather than tabs */
  2256. if (text->flags & TXT_TABSTOSPACES) {
  2257. add = tab_to_spaces;
  2258. indentlen = spaceslen;
  2259. }
  2260. num = 0;
  2261. while (TRUE)
  2262. {
  2263. tmp= MEM_mallocN(text->curl->len+indentlen+1, "textline_string");
  2264. text->curc = 0;
  2265. if (text->curc) memcpy(tmp, text->curl->line, text->curc); /* XXX never true, check prev line */
  2266. memcpy(tmp+text->curc, add, indentlen);
  2267. len= text->curl->len - text->curc;
  2268. if (len>0) memcpy(tmp+text->curc+indentlen, text->curl->line+text->curc, len);
  2269. tmp[text->curl->len+indentlen]= 0;
  2270. make_new_line(text->curl, tmp);
  2271. text->curc+= indentlen;
  2272. txt_make_dirty(text);
  2273. txt_clean_text(text);
  2274. if (text->curl == text->sell)
  2275. {
  2276. text->selc = text->sell->len;
  2277. break;
  2278. }
  2279. else {
  2280. text->curl = text->curl->next;
  2281. num++;
  2282. }
  2283. }
  2284. text->curc = 0;
  2285. while ( num > 0 )
  2286. {
  2287. text->curl = text->curl->prev;
  2288. num--;
  2289. }
  2290. if (!undoing)
  2291. {
  2292. 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);
  2293. }
  2294. }
  2295. void txt_unindent(Text *text)
  2296. {
  2297. int num = 0;
  2298. const char *remove = "\t";
  2299. int indent = 1;
  2300. /* hardcoded: TXT_TABSIZE = 4 spaces: */
  2301. int spaceslen = TXT_TABSIZE;
  2302. if (!text) return;
  2303. if (!text->curl) return;
  2304. if (!text->sell) return;
  2305. /* insert spaces rather than tabs */
  2306. if (text->flags & TXT_TABSTOSPACES) {
  2307. remove = tab_to_spaces;
  2308. indent = spaceslen;
  2309. }
  2310. while (TRUE)
  2311. {
  2312. int i = 0;
  2313. if (BLI_strncasecmp(text->curl->line, remove, indent) == 0)
  2314. {
  2315. while (i< text->curl->len) {
  2316. text->curl->line[i]= text->curl->line[i+indent];
  2317. i++;
  2318. }
  2319. text->curl->len-= indent;
  2320. }
  2321. txt_make_dirty(text);
  2322. txt_clean_text(text);
  2323. if (text->curl == text->sell)
  2324. {
  2325. text->selc = text->sell->len;
  2326. break;
  2327. }
  2328. else {
  2329. text->curl = text->curl->next;
  2330. num++;
  2331. }
  2332. }
  2333. text->curc = 0;
  2334. while ( num > 0 )
  2335. {
  2336. text->curl = text->curl->prev;
  2337. num--;
  2338. }
  2339. if (!undoing)
  2340. {
  2341. 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);
  2342. }
  2343. }
  2344. void txt_comment(Text *text)
  2345. {
  2346. int len, num;
  2347. char *tmp;
  2348. char add = '#';
  2349. if (!text) return;
  2350. if (!text->curl) return;
  2351. if (!text->sell) return;// Need to change this need to check if only one line is selected to more then one
  2352. num = 0;
  2353. while (TRUE)
  2354. {
  2355. tmp= MEM_mallocN(text->curl->len+2, "textline_string");
  2356. text->curc = 0;
  2357. if (text->curc) memcpy(tmp, text->curl->line, text->curc);
  2358. tmp[text->curc]= add;
  2359. len= text->curl->len - text->curc;
  2360. if (len>0) memcpy(tmp+text->curc+1, text->curl->line+text->curc, len);
  2361. tmp[text->curl->len+1]=0;
  2362. make_new_line(text->curl, tmp);
  2363. text->curc++;
  2364. txt_make_dirty(text);
  2365. txt_clean_text(text);
  2366. if (text->curl == text->sell)
  2367. {
  2368. text->selc = text->sell->len;
  2369. break;
  2370. }
  2371. else {
  2372. text->curl = text->curl->next;
  2373. num++;
  2374. }
  2375. }
  2376. text->curc = 0;
  2377. while ( num > 0 )
  2378. {
  2379. text->curl = text->curl->prev;
  2380. num--;
  2381. }
  2382. if (!undoing)
  2383. {
  2384. 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);
  2385. }
  2386. }
  2387. void txt_uncomment(Text *text)
  2388. {
  2389. int num = 0;
  2390. char remove = '#';
  2391. if (!text) return;
  2392. if (!text->curl) return;
  2393. if (!text->sell) return;
  2394. while (TRUE)
  2395. {
  2396. int i = 0;
  2397. if (text->curl->line[i] == remove)
  2398. {
  2399. while (i< text->curl->len) {
  2400. text->curl->line[i]= text->curl->line[i+1];
  2401. i++;
  2402. }
  2403. text->curl->len--;
  2404. }
  2405. txt_make_dirty(text);
  2406. txt_clean_text(text);
  2407. if (text->curl == text->sell)
  2408. {
  2409. text->selc = text->sell->len;
  2410. break;
  2411. }
  2412. else {
  2413. text->curl = text->curl->next;
  2414. num++;
  2415. }
  2416. }
  2417. text->curc = 0;
  2418. while ( num > 0 )
  2419. {
  2420. text->curl = text->curl->prev;
  2421. num--;
  2422. }
  2423. if (!undoing)
  2424. {
  2425. 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);
  2426. }
  2427. }
  2428. int setcurr_tab_spaces (Text *text, int space)
  2429. {
  2430. int i = 0;
  2431. int test = 0;
  2432. const char *word = ":";
  2433. const char *comm = "#";
  2434. const char indent= (text->flags & TXT_TABSTOSPACES) ? ' ' : '\t';
  2435. static const char *back_words[]= {"return", "break", "continue", "pass", "yield", NULL};
  2436. if (!text) return 0;
  2437. if (!text->curl) return 0;
  2438. while (text->curl->line[i] == indent)
  2439. {
  2440. //we only count those tabs/spaces that are before any text or before the curs;
  2441. if (i == text->curc)
  2442. {
  2443. return i;
  2444. }
  2445. else {
  2446. i++;
  2447. }
  2448. }
  2449. if (strstr(text->curl->line, word))
  2450. {
  2451. /* if we find a ':' on this line, then add a tab but not if it is:
  2452. * 1) in a comment
  2453. * 2) within an identifier
  2454. * 3) after the cursor (text->curc), i.e. when creating space before a function def [#25414]
  2455. */
  2456. int a, is_indent = 0;
  2457. for (a=0; (a < text->curc) && (text->curl->line[a] != '\0'); a++)
  2458. {
  2459. char ch= text->curl->line[a];
  2460. if (ch=='#') {
  2461. break;
  2462. }
  2463. else if (ch==':') {
  2464. is_indent = 1;
  2465. }
  2466. else if (ch!=' ' && ch!='\t') {
  2467. is_indent = 0;
  2468. }
  2469. }
  2470. if (is_indent) {
  2471. i += space;
  2472. }
  2473. }
  2474. for (test=0; back_words[test]; test++)
  2475. {
  2476. /* if there are these key words then remove a tab because we are done with the block */
  2477. if (strstr(text->curl->line, back_words[test]) && i > 0)
  2478. {
  2479. if (strcspn(text->curl->line, back_words[test]) < strcspn(text->curl->line, comm))
  2480. {
  2481. i -= space;
  2482. }
  2483. }
  2484. }
  2485. return i;
  2486. }
  2487. /*********************************/
  2488. /* Text marker utility functions */
  2489. /*********************************/
  2490. /* Creates and adds a marker to the list maintaining sorted order */
  2491. void txt_add_marker(Text *text, TextLine *line, int start, int end, const unsigned char color[4], int group, int flags)
  2492. {
  2493. TextMarker *tmp, *marker;
  2494. marker= MEM_mallocN(sizeof(TextMarker), "text_marker");
  2495. marker->lineno= txt_get_span(text->lines.first, line);
  2496. marker->start= MIN2(start, end);
  2497. marker->end= MAX2(start, end);
  2498. marker->group= group;
  2499. marker->flags= flags;
  2500. marker->color[0]= color[0];
  2501. marker->color[1]= color[1];
  2502. marker->color[2]= color[2];
  2503. marker->color[3]= color[3];
  2504. for (tmp=text->markers.last; tmp; tmp=tmp->prev)
  2505. if (tmp->lineno < marker->lineno || (tmp->lineno==marker->lineno && tmp->start < marker->start))
  2506. break;
  2507. if (tmp) BLI_insertlinkafter(&text->markers, tmp, marker);
  2508. else BLI_addhead(&text->markers, marker);
  2509. }
  2510. /* Returns the first matching marker on the specified line between two points.
  2511. * If the group or flags fields are non-zero the returned flag must be in the
  2512. * specified group and have at least the specified flags set. */
  2513. TextMarker *txt_find_marker_region(Text *text, TextLine *line, int start, int end, int group, int flags)
  2514. {
  2515. TextMarker *marker, *next;
  2516. int lineno= txt_get_span(text->lines.first, line);
  2517. for (marker=text->markers.first; marker; marker=next) {
  2518. next= marker->next;
  2519. if (group && marker->group != group) continue;
  2520. else if ((marker->flags & flags) != flags) continue;
  2521. else if (marker->lineno < lineno) continue;
  2522. else if (marker->lineno > lineno) break;
  2523. if ((marker->start==marker->end && start<=marker->start && marker->start<=end) ||
  2524. (marker->start<end && marker->end>start))
  2525. return marker;
  2526. }
  2527. return NULL;
  2528. }
  2529. /* Clears all markers on the specified line between two points. If the group or
  2530. * flags fields are non-zero the returned flag must be in the specified group
  2531. * and have at least the specified flags set. */
  2532. short txt_clear_marker_region(Text *text, TextLine *line, int start, int end, int group, int flags)
  2533. {
  2534. TextMarker *marker, *next;
  2535. int lineno= txt_get_span(text->lines.first, line);
  2536. short cleared= 0;
  2537. for (marker=text->markers.first; marker; marker=next) {
  2538. next= marker->next;
  2539. if (group && marker->group != group) continue;
  2540. else if ((marker->flags & flags) != flags) continue;
  2541. else if (marker->lineno < lineno) continue;
  2542. else if (marker->lineno > lineno) break;
  2543. if ((marker->start==marker->end && start<=marker->start && marker->start<=end) ||
  2544. (marker->start<end && marker->end>start)) {
  2545. BLI_freelinkN(&text->markers, marker);
  2546. cleared= 1;
  2547. }
  2548. }
  2549. return cleared;
  2550. }
  2551. /* Clears all markers in the specified group (if given) with at least the
  2552. * specified flags set. Useful for clearing temporary markers (group=0,
  2553. * flags=TMARK_TEMP) */
  2554. short txt_clear_markers(Text *text, int group, int flags)
  2555. {
  2556. TextMarker *marker, *next;
  2557. short cleared= 0;
  2558. for (marker=text->markers.first; marker; marker=next) {
  2559. next= marker->next;
  2560. if ((!group || marker->group==group) &&
  2561. (marker->flags & flags) == flags) {
  2562. BLI_freelinkN(&text->markers, marker);
  2563. cleared= 1;
  2564. }
  2565. }
  2566. return cleared;
  2567. }
  2568. /* Finds the marker at the specified line and cursor position with at least the
  2569. * specified flags set in the given group (if non-zero). */
  2570. TextMarker *txt_find_marker(Text *text, TextLine *line, int curs, int group, int flags)
  2571. {
  2572. TextMarker *marker;
  2573. int lineno= txt_get_span(text->lines.first, line);
  2574. for (marker=text->markers.first; marker; marker=marker->next) {
  2575. if (group && marker->group != group) continue;
  2576. else if ((marker->flags & flags) != flags) continue;
  2577. else if (marker->lineno < lineno) continue;
  2578. else if (marker->lineno > lineno) break;
  2579. if (marker->start <= curs && curs <= marker->end)
  2580. return marker;
  2581. }
  2582. return NULL;
  2583. }
  2584. /* Finds the previous marker in the same group. If no other is found, the same
  2585. * marker will be returned */
  2586. TextMarker *txt_prev_marker(Text *text, TextMarker *marker)
  2587. {
  2588. TextMarker *tmp= marker;
  2589. while (tmp) {
  2590. if (tmp->prev) tmp= tmp->prev;
  2591. else tmp= text->markers.last;
  2592. if (tmp->group == marker->group)
  2593. return tmp;
  2594. }
  2595. return NULL; /* Only if marker==NULL */
  2596. }
  2597. /* Finds the next marker in the same group. If no other is found, the same
  2598. * marker will be returned */
  2599. TextMarker *txt_next_marker(Text *text, TextMarker *marker)
  2600. {
  2601. TextMarker *tmp= marker;
  2602. while (tmp) {
  2603. if (tmp->next) tmp= tmp->next;
  2604. else tmp= text->markers.first;
  2605. if (tmp->group == marker->group)
  2606. return tmp;
  2607. }
  2608. return NULL; /* Only if marker==NULL */
  2609. }
  2610. /*******************************/
  2611. /* Character utility functions */
  2612. /*******************************/
  2613. int text_check_bracket(const char ch)
  2614. {
  2615. int a;
  2616. char opens[] = "([{";
  2617. char close[] = ")]}";
  2618. for (a=0; a<(sizeof(opens)-1); a++) {
  2619. if (ch==opens[a])
  2620. return a+1;
  2621. else if (ch==close[a])
  2622. return -(a+1);
  2623. }
  2624. return 0;
  2625. }
  2626. /* TODO, have a function for operators - http://docs.python.org/py3k/reference/lexical_analysis.html#operators */
  2627. int text_check_delim(const char ch)
  2628. {
  2629. int a;
  2630. char delims[] = "():\"\' ~!%^&*-+=[]{};/<>|.#\t,@";
  2631. for (a=0; a<(sizeof(delims)-1); a++) {
  2632. if (ch==delims[a])
  2633. return 1;
  2634. }
  2635. return 0;
  2636. }
  2637. int text_check_digit(const char ch)
  2638. {
  2639. if (ch < '0') return 0;
  2640. if (ch <= '9') return 1;
  2641. return 0;
  2642. }
  2643. int text_check_identifier(const char ch)
  2644. {
  2645. if (ch < '0') return 0;
  2646. if (ch <= '9') return 1;
  2647. if (ch < 'A') return 0;
  2648. if (ch <= 'Z' || ch == '_') return 1;
  2649. if (ch < 'a') return 0;
  2650. if (ch <= 'z') return 1;
  2651. return 0;
  2652. }
  2653. int text_check_whitespace(const char ch)
  2654. {
  2655. if (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n')
  2656. return 1;
  2657. return 0;
  2658. }