PageRenderTime 31ms CodeModel.GetById 25ms 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

Large files files are truncated, but you can click here to view the full file

  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. i

Large files files are truncated, but you can click here to view the full file