/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
- /*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): none yet.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
- /** \file blender/blenkernel/intern/text.c
- * \ingroup bke
- */
- #include <stdlib.h> /* abort */
- #include <string.h> /* strstr */
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <wchar.h>
- #include <wctype.h>
- #include "MEM_guardedalloc.h"
- #include "BLI_path_util.h"
- #include "BLI_string.h"
- #include "BLI_string_cursor_utf8.h"
- #include "BLI_string_utf8.h"
- #include "BLI_listbase.h"
- #include "BLI_utildefines.h"
- #include "BLI_fileops.h"
- #include "DNA_constraint_types.h"
- #include "DNA_controller_types.h"
- #include "DNA_scene_types.h"
- #include "DNA_screen_types.h"
- #include "DNA_space_types.h"
- #include "DNA_text_types.h"
- #include "DNA_userdef_types.h"
- #include "DNA_object_types.h"
- #include "BKE_depsgraph.h"
- #include "BKE_global.h"
- #include "BKE_library.h"
- #include "BKE_main.h"
- #include "BKE_text.h"
- #ifdef WITH_PYTHON
- #include "BPY_extern.h"
- #endif
- /*
- * How Texts should work
- * --
- * A text should relate to a file as follows -
- * (Text *)->name should be the place where the
- * file will or has been saved.
- *
- * (Text *)->flags has the following bits
- * TXT_ISDIRTY - should always be set if the file in mem. differs from
- * the file on disk, or if there is no file on disk.
- * TXT_ISMEM - should always be set if the Text has not been mapped to
- * a file, in which case (Text *)->name may be NULL or garbage.
- * TXT_ISEXT - should always be set if the Text is not to be written into
- * the .blend
- * TXT_ISSCRIPT - should be set if the user has designated the text
- * as a script. (NEW: this was unused, but now it is needed by
- * space handler script links (see header_view3d.c, for example)
- *
- * ->>> see also: /makesdna/DNA_text_types.h
- *
- * Display
- * --
- * The st->top determines at what line the top of the text is displayed.
- * If the user moves the cursor the st containing that cursor should
- * be popped ... other st's retain their own top location.
- *
- * Markers
- * --
- * The mrk->flags define the behavior and relationships between markers. The
- * upper two bytes are used to hold a group ID, the lower two are normal flags. If
- * TMARK_EDITALL is set the group ID defines which other markers should be edited.
- *
- * The mrk->clr field is used to visually group markers where the flags may not
- * match. A template system, for example, may allow editing of repeating tokens
- * (in one group) but include other marked positions (in another group) all in the
- * same template with the same color.
- *
- * Undo
- * --
- * Undo/Redo works by storing
- * events in a queue, and a pointer
- * to the current position in the
- * queue...
- *
- * Events are stored using an
- * arbitrary op-code system
- * to keep track of
- * a) the two cursors (normal and selected)
- * b) input (visible and control (ie backspace))
- *
- * input data is stored as its
- * ASCII value, the opcodes are
- * then selected to not conflict.
- *
- * opcodes with data in between are
- * written at the beginning and end
- * of the data to allow undo and redo
- * to simply check the code at the current
- * undo position
- *
- */
- /***/
- static void txt_pop_first(Text *text);
- static void txt_pop_last(Text *text);
- static void txt_undo_add_op(Text *text, int op);
- static void txt_undo_add_block(Text *text, int op, const char *buf);
- static void txt_delete_line(Text *text, TextLine *line);
- static void txt_delete_sel (Text *text);
- static void txt_make_dirty (Text *text);
- /***/
- static unsigned char undoing;
- /* allow to switch off undoing externally */
- void txt_set_undostate(int u)
- {
- undoing = u;
- }
- int txt_get_undostate(void)
- {
- return undoing;
- }
- static void init_undo_text(Text *text)
- {
- text->undo_pos= -1;
- text->undo_len= TXT_INIT_UNDO;
- text->undo_buf= MEM_mallocN(text->undo_len, "undo buf");
- }
- void free_text(Text *text)
- {
- TextLine *tmp;
- for (tmp= text->lines.first; tmp; tmp= tmp->next) {
- MEM_freeN(tmp->line);
- if (tmp->format)
- MEM_freeN(tmp->format);
- }
-
- BLI_freelistN(&text->lines);
- BLI_freelistN(&text->markers);
- if (text->name) MEM_freeN(text->name);
- MEM_freeN(text->undo_buf);
- #ifdef WITH_PYTHON
- if (text->compiled) BPY_text_free_code(text);
- #endif
- }
- Text *add_empty_text(const char *name)
- {
- Main *bmain= G.main;
- Text *ta;
- TextLine *tmp;
-
- ta= alloc_libblock(&bmain->text, ID_TXT, name);
- ta->id.us= 1;
-
- ta->name= NULL;
- init_undo_text(ta);
- ta->nlines=1;
- ta->flags= TXT_ISDIRTY | TXT_ISMEM;
- if ((U.flag & USER_TXT_TABSTOSPACES_DISABLE)==0)
- ta->flags |= TXT_TABSTOSPACES;
- ta->lines.first= ta->lines.last= NULL;
- ta->markers.first= ta->markers.last= NULL;
- tmp= (TextLine*) MEM_mallocN(sizeof(TextLine), "textline");
- tmp->line= (char*) MEM_mallocN(1, "textline_string");
- tmp->format= NULL;
-
- tmp->line[0]=0;
- tmp->len= 0;
-
- tmp->next= NULL;
- tmp->prev= NULL;
-
- BLI_addhead(&ta->lines, tmp);
-
- ta->curl= ta->lines.first;
- ta->curc= 0;
- ta->sell= ta->lines.first;
- ta->selc= 0;
- return ta;
- }
- /* this function replaces extended ascii characters */
- /* to a valid utf-8 sequences */
- int txt_extended_ascii_as_utf8(char **str)
- {
- int bad_char, added= 0, i= 0;
- int length = strlen(*str);
- while ((*str)[i]) {
- if ((bad_char= BLI_utf8_invalid_byte(*str+i, length-i)) == -1)
- break;
- added++;
- i+= bad_char + 1;
- }
-
- if (added != 0) {
- char *newstr = MEM_mallocN(length+added+1, "text_line");
- int mi = 0;
- i= 0;
-
- while ((*str)[i]) {
- if ((bad_char= BLI_utf8_invalid_byte((*str)+i, length-i)) == -1) {
- memcpy(newstr+mi, (*str)+i, length - i + 1);
- break;
- }
-
- memcpy(newstr+mi, (*str)+i, bad_char);
- BLI_str_utf8_from_unicode((*str)[i+bad_char], newstr+mi+bad_char);
- i+= bad_char+1;
- mi+= bad_char+2;
- }
- newstr[length+added] = '\0';
- MEM_freeN(*str);
- *str = newstr;
- }
-
- return added;
- }
- // this function removes any control characters from
- // a textline and fixes invalid utf-8 sequences
- static void cleanup_textline(TextLine * tl)
- {
- int i;
- for (i = 0; i < tl->len; i++ ) {
- if (tl->line[i] < ' ' && tl->line[i] != '\t') {
- memmove(tl->line + i, tl->line + i + 1, tl->len - i);
- tl->len--;
- i--;
- }
- }
- tl->len+= txt_extended_ascii_as_utf8(&tl->line);
- }
- int reopen_text(Text *text)
- {
- FILE *fp;
- int i, llen, len;
- unsigned char *buffer;
- TextLine *tmp;
- char str[FILE_MAX];
- struct stat st;
- if (!text || !text->name) return 0;
-
- BLI_strncpy(str, text->name, FILE_MAX);
- BLI_path_abs(str, G.main->name);
-
- fp= BLI_fopen(str, "r");
- if (fp==NULL) return 0;
- /* free memory: */
- for (tmp= text->lines.first; tmp; tmp= tmp->next) {
- MEM_freeN(tmp->line);
- if (tmp->format) MEM_freeN(tmp->format);
- }
-
- BLI_freelistN(&text->lines);
- text->lines.first= text->lines.last= NULL;
- text->curl= text->sell= NULL;
- /* clear undo buffer */
- MEM_freeN(text->undo_buf);
- init_undo_text(text);
-
- fseek(fp, 0L, SEEK_END);
- len= ftell(fp);
- fseek(fp, 0L, SEEK_SET);
- text->undo_pos= -1;
-
- buffer= MEM_mallocN(len, "text_buffer");
- // under windows fread can return less then len bytes because
- // of CR stripping
- len = fread(buffer, 1, len, fp);
- fclose(fp);
- stat(str, &st);
- text->mtime= st.st_mtime;
-
- text->nlines=0;
- llen=0;
- for (i=0; i<len; i++) {
- if (buffer[i]=='\n') {
- tmp= (TextLine*) MEM_mallocN(sizeof(TextLine), "textline");
- tmp->line= (char*) MEM_mallocN(llen+1, "textline_string");
- tmp->format= NULL;
-
- if (llen) memcpy(tmp->line, &buffer[i-llen], llen);
- tmp->line[llen]=0;
- tmp->len= llen;
-
- cleanup_textline(tmp);
- BLI_addtail(&text->lines, tmp);
- text->nlines++;
-
- llen=0;
- continue;
- }
- llen++;
- }
- if (llen!=0 || text->nlines==0) {
- tmp= (TextLine*) MEM_mallocN(sizeof(TextLine), "textline");
- tmp->line= (char*) MEM_mallocN(llen+1, "textline_string");
- tmp->format= NULL;
-
- if (llen) memcpy(tmp->line, &buffer[i-llen], llen);
- tmp->line[llen]=0;
- tmp->len= llen;
-
- cleanup_textline(tmp);
- BLI_addtail(&text->lines, tmp);
- text->nlines++;
- }
-
- text->curl= text->sell= text->lines.first;
- text->curc= text->selc= 0;
-
- MEM_freeN(buffer);
- return 1;
- }
- Text *add_text(const char *file, const char *relpath)
- {
- Main *bmain= G.main;
- FILE *fp;
- int i, llen, len;
- unsigned char *buffer;
- TextLine *tmp;
- Text *ta;
- char str[FILE_MAX];
- struct stat st;
- BLI_strncpy(str, file, FILE_MAX);
- if (relpath) /* can be NULL (bg mode) */
- BLI_path_abs(str, relpath);
-
- fp= BLI_fopen(str, "r");
- if (fp==NULL) return NULL;
-
- ta= alloc_libblock(&bmain->text, ID_TXT, BLI_path_basename(str));
- ta->id.us= 1;
- ta->lines.first= ta->lines.last= NULL;
- ta->markers.first= ta->markers.last= NULL;
- ta->curl= ta->sell= NULL;
- if ((U.flag & USER_TXT_TABSTOSPACES_DISABLE)==0)
- ta->flags= TXT_TABSTOSPACES;
- fseek(fp, 0L, SEEK_END);
- len= ftell(fp);
- fseek(fp, 0L, SEEK_SET);
- ta->name= MEM_mallocN(strlen(file)+1, "text_name");
- strcpy(ta->name, file);
- init_undo_text(ta);
-
- buffer= MEM_mallocN(len, "text_buffer");
- // under windows fread can return less then len bytes because
- // of CR stripping
- len = fread(buffer, 1, len, fp);
- fclose(fp);
- stat(str, &st);
- ta->mtime= st.st_mtime;
-
- ta->nlines=0;
- llen=0;
- for (i=0; i<len; i++) {
- if (buffer[i]=='\n') {
- tmp= (TextLine*) MEM_mallocN(sizeof(TextLine), "textline");
- tmp->line= (char*) MEM_mallocN(llen+1, "textline_string");
- tmp->format= NULL;
-
- if (llen) memcpy(tmp->line, &buffer[i-llen], llen);
- tmp->line[llen]=0;
- tmp->len= llen;
-
- cleanup_textline(tmp);
- BLI_addtail(&ta->lines, tmp);
- ta->nlines++;
-
- llen=0;
- continue;
- }
- llen++;
- }
- /* create new line in cases:
- * - rest of line (if last line in file hasn't got \n terminator).
- * in this case content of such line would be used to fill text line buffer
- * - file is empty. in this case new line is needed to start editing from.
- * - last characted in buffer is \n. in this case new line is needed to
- * deal with newline at end of file. (see [#28087]) (sergey) */
- if (llen!=0 || ta->nlines==0 || buffer[len-1]=='\n') {
- tmp= (TextLine*) MEM_mallocN(sizeof(TextLine), "textline");
- tmp->line= (char*) MEM_mallocN(llen+1, "textline_string");
- tmp->format= NULL;
-
- if (llen) memcpy(tmp->line, &buffer[i-llen], llen);
- tmp->line[llen]=0;
- tmp->len= llen;
-
- cleanup_textline(tmp);
- BLI_addtail(&ta->lines, tmp);
- ta->nlines++;
- }
-
- ta->curl= ta->sell= ta->lines.first;
- ta->curc= ta->selc= 0;
-
- MEM_freeN(buffer);
- return ta;
- }
- Text *copy_text(Text *ta)
- {
- Text *tan;
- TextLine *line, *tmp;
-
- tan= copy_libblock(&ta->id);
-
- /* file name can be NULL */
- if (ta->name) {
- tan->name= MEM_mallocN(strlen(ta->name)+1, "text_name");
- strcpy(tan->name, ta->name);
- }
- else {
- tan->name= NULL;
- }
- tan->flags = ta->flags | TXT_ISDIRTY;
-
- tan->lines.first= tan->lines.last= NULL;
- tan->markers.first= tan->markers.last= NULL;
- tan->curl= tan->sell= NULL;
-
- tan->nlines= ta->nlines;
- line= ta->lines.first;
- /* Walk down, reconstructing */
- while (line) {
- tmp= (TextLine*) MEM_mallocN(sizeof(TextLine), "textline");
- tmp->line= MEM_mallocN(line->len+1, "textline_string");
- tmp->format= NULL;
-
- strcpy(tmp->line, line->line);
- tmp->len= line->len;
-
- BLI_addtail(&tan->lines, tmp);
-
- line= line->next;
- }
- tan->curl= tan->sell= tan->lines.first;
- tan->curc= tan->selc= 0;
- init_undo_text(tan);
- return tan;
- }
- void unlink_text(Main *bmain, Text *text)
- {
- bScreen *scr;
- ScrArea *area;
- SpaceLink *sl;
- Object *ob;
- bController *cont;
- bConstraint *con;
- short update;
- for (ob=bmain->object.first; ob; ob=ob->id.next) {
- /* game controllers */
- for (cont=ob->controllers.first; cont; cont=cont->next) {
- if (cont->type==CONT_PYTHON) {
- bPythonCont *pc;
-
- pc= cont->data;
- if (pc->text==text) pc->text= NULL;
- }
- }
- /* pyconstraints */
- update = 0;
- if (ob->type==OB_ARMATURE && ob->pose) {
- bPoseChannel *pchan;
- for (pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
- for (con = pchan->constraints.first; con; con=con->next) {
- if (con->type==CONSTRAINT_TYPE_PYTHON) {
- bPythonConstraint *data = con->data;
- if (data->text==text) data->text = NULL;
- update = 1;
-
- }
- }
- }
- }
- for (con = ob->constraints.first; con; con=con->next) {
- if (con->type==CONSTRAINT_TYPE_PYTHON) {
- bPythonConstraint *data = con->data;
- if (data->text==text) data->text = NULL;
- update = 1;
- }
- }
-
- if (update)
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
- }
- /* pynodes */
- // XXX nodeDynamicUnlinkText(&text->id);
-
- /* text space */
- for (scr= bmain->screen.first; scr; scr= scr->id.next) {
- for (area= scr->areabase.first; area; area= area->next) {
- for (sl= area->spacedata.first; sl; sl= sl->next) {
- if (sl->spacetype==SPACE_TEXT) {
- SpaceText *st= (SpaceText*) sl;
-
- if (st->text==text) {
- st->text= NULL;
- st->top= 0;
- }
- }
- }
- }
- }
- text->id.us= 0;
- }
- void clear_text(Text *text) /* called directly from rna */
- {
- int oldstate;
- oldstate = txt_get_undostate( );
- txt_set_undostate( 1 );
- txt_sel_all( text );
- txt_delete_sel(text);
- txt_set_undostate(oldstate);
- txt_make_dirty(text);
- }
- void write_text(Text *text, const char *str) /* called directly from rna */
- {
- int oldstate;
- oldstate = txt_get_undostate();
- txt_insert_buf(text, str);
- txt_move_eof(text, 0);
- txt_set_undostate(oldstate);
- txt_make_dirty(text);
- }
- /*****************************/
- /* Editing utility functions */
- /*****************************/
- static void make_new_line(TextLine *line, char *newline)
- {
- if (line->line) MEM_freeN(line->line);
- if (line->format) MEM_freeN(line->format);
-
- line->line= newline;
- line->len= strlen(newline);
- line->format= NULL;
- }
- static TextLine *txt_new_line(const char *str)
- {
- TextLine *tmp;
- if (!str) str= "";
-
- tmp= (TextLine *) MEM_mallocN(sizeof(TextLine), "textline");
- tmp->line= MEM_mallocN(strlen(str)+1, "textline_string");
- tmp->format= NULL;
-
- strcpy(tmp->line, str);
-
- tmp->len= strlen(str);
- tmp->next= tmp->prev= NULL;
-
- return tmp;
- }
- static TextLine *txt_new_linen(const char *str, int n)
- {
- TextLine *tmp;
- tmp= (TextLine *) MEM_mallocN(sizeof(TextLine), "textline");
- tmp->line= MEM_mallocN(n+1, "textline_string");
- tmp->format= NULL;
-
- BLI_strncpy(tmp->line, (str)? str: "", n+1);
-
- tmp->len= strlen(tmp->line);
- tmp->next= tmp->prev= NULL;
-
- return tmp;
- }
- void txt_clean_text (Text *text)
- {
- TextLine **top, **bot;
-
- if (!text) return;
-
- if (!text->lines.first) {
- if (text->lines.last) text->lines.first= text->lines.last;
- else text->lines.first= text->lines.last= txt_new_line(NULL);
- }
-
- if (!text->lines.last) text->lines.last= text->lines.first;
- top= (TextLine **) &text->lines.first;
- bot= (TextLine **) &text->lines.last;
-
- while ((*top)->prev) *top= (*top)->prev;
- while ((*bot)->next) *bot= (*bot)->next;
- if (!text->curl) {
- if (text->sell) text->curl= text->sell;
- else text->curl= text->lines.first;
- text->curc= 0;
- }
- if (!text->sell) {
- text->sell= text->curl;
- text->selc= 0;
- }
- }
- int txt_get_span (TextLine *from, TextLine *to)
- {
- int ret=0;
- TextLine *tmp= from;
- if (!to || !from) return 0;
- if (from==to) return 0;
- /* Look forwards */
- while (tmp) {
- if (tmp == to) return ret;
- ret++;
- tmp= tmp->next;
- }
- /* Look backwards */
- if (!tmp) {
- tmp= from;
- ret=0;
- while (tmp) {
- if (tmp == to) break;
- ret--;
- tmp= tmp->prev;
- }
- if (!tmp) ret=0;
- }
- return ret;
- }
- static void txt_make_dirty (Text *text)
- {
- text->flags |= TXT_ISDIRTY;
- #ifdef WITH_PYTHON
- if (text->compiled) BPY_text_free_code(text);
- #endif
- }
- /****************************/
- /* Cursor utility functions */
- /****************************/
- static void txt_curs_cur (Text *text, TextLine ***linep, int **charp)
- {
- *linep= &text->curl; *charp= &text->curc;
- }
- static void txt_curs_sel (Text *text, TextLine ***linep, int **charp)
- {
- *linep= &text->sell; *charp= &text->selc;
- }
- static void txt_curs_first (Text *text, TextLine **linep, int *charp)
- {
- if (text->curl==text->sell) {
- *linep= text->curl;
- if (text->curc<text->selc) *charp= text->curc;
- else *charp= text->selc;
- }
- else if (txt_get_span(text->lines.first, text->curl)<txt_get_span(text->lines.first, text->sell)) {
- *linep= text->curl;
- *charp= text->curc;
- }
- else {
- *linep= text->sell;
- *charp= text->selc;
- }
- }
- /*****************************/
- /* Cursor movement functions */
- /*****************************/
- int txt_utf8_offset_to_index(const char *str, int offset)
- {
- int index= 0, pos= 0;
- while (pos != offset) {
- pos += BLI_str_utf8_size(str + pos);
- index++;
- }
- return index;
- }
- int txt_utf8_index_to_offset(const char *str, int index)
- {
- int offset= 0, pos= 0;
- while (pos != index) {
- offset += BLI_str_utf8_size(str + offset);
- pos++;
- }
- return offset;
- }
- /* returns the real number of characters in string */
- /* not the same as BLI_strlen_utf8, which returns length for wide characters */
- static int txt_utf8_len(const char *src)
- {
- int len;
- for (len=0; *src; len++) {
- src += BLI_str_utf8_size(src);
- }
- return len;
- }
- void txt_move_up(Text *text, short sel)
- {
- TextLine **linep;
- int *charp;
- /* int old; */ /* UNUSED */
-
- if (!text) return;
- if (sel) txt_curs_sel(text, &linep, &charp);
- else { txt_pop_first(text); txt_curs_cur(text, &linep, &charp); }
- if (!*linep) return;
- /* old= *charp; */ /* UNUSED */
- if ((*linep)->prev) {
- int index = txt_utf8_offset_to_index((*linep)->line, *charp);
- *linep= (*linep)->prev;
- if (index > txt_utf8_len((*linep)->line)) *charp= (*linep)->len;
- else *charp= txt_utf8_index_to_offset((*linep)->line, index);
-
- if (!undoing)
- txt_undo_add_op(text, sel?UNDO_SUP:UNDO_CUP);
- }
- else {
- txt_move_bol(text, sel);
- }
- if (!sel) txt_pop_sel(text);
- }
- void txt_move_down(Text *text, short sel)
- {
- TextLine **linep;
- int *charp;
- /* int old; */ /* UNUSED */
-
- if (!text) return;
- if (sel) txt_curs_sel(text, &linep, &charp);
- else { txt_pop_last(text); txt_curs_cur(text, &linep, &charp); }
- if (!*linep) return;
- /* old= *charp; */ /* UNUSED */
- if ((*linep)->next) {
- int index = txt_utf8_offset_to_index((*linep)->line, *charp);
- *linep= (*linep)->next;
- if (index > txt_utf8_len((*linep)->line)) *charp= (*linep)->len;
- else *charp= txt_utf8_index_to_offset((*linep)->line, index);
-
- if (!undoing)
- txt_undo_add_op(text, sel?UNDO_SDOWN:UNDO_CDOWN);
- }
- else {
- txt_move_eol(text, sel);
- }
- if (!sel) txt_pop_sel(text);
- }
- void txt_move_left(Text *text, short sel)
- {
- TextLine **linep;
- int *charp, oundoing= undoing;
- int tabsize= 0, i= 0;
-
- if (!text) return;
- if (sel) txt_curs_sel(text, &linep, &charp);
- else { txt_pop_first(text); txt_curs_cur(text, &linep, &charp); }
- if (!*linep) return;
- undoing= 1;
- if (*charp== 0) {
- if ((*linep)->prev) {
- txt_move_up(text, sel);
- *charp= (*linep)->len;
- }
- }
- else {
- // do nice left only if there are only spaces
- // TXT_TABSIZE hardcoded in DNA_text_types.h
- if (text->flags & TXT_TABSTOSPACES) {
- tabsize= (*charp < TXT_TABSIZE) ? *charp : TXT_TABSIZE;
-
- for (i=0; i<(*charp); i++)
- if ((*linep)->line[i] != ' ') {
- tabsize= 0;
- break;
- }
-
- // if in the middle of the space-tab
- if (tabsize && (*charp) % TXT_TABSIZE != 0)
- tabsize= ((*charp) % TXT_TABSIZE);
- }
-
- if (tabsize)
- (*charp)-= tabsize;
- else {
- const char *prev= BLI_str_prev_char_utf8((*linep)->line + *charp);
- *charp= prev - (*linep)->line;
- }
- }
- undoing= oundoing;
- if (!undoing) txt_undo_add_op(text, sel?UNDO_SLEFT:UNDO_CLEFT);
-
- if (!sel) txt_pop_sel(text);
- }
- void txt_move_right(Text *text, short sel)
- {
- TextLine **linep;
- int *charp, oundoing= undoing, do_tab= 0, i;
-
- if (!text) return;
- if (sel) txt_curs_sel(text, &linep, &charp);
- else { txt_pop_last(text); txt_curs_cur(text, &linep, &charp); }
- if (!*linep) return;
- undoing= 1;
- if (*charp== (*linep)->len) {
- if ((*linep)->next) {
- txt_move_down(text, sel);
- *charp= 0;
- }
- }
- else {
- // do nice right only if there are only spaces
- // spaces hardcoded in DNA_text_types.h
- if (text->flags & TXT_TABSTOSPACES && (*linep)->line[*charp]== ' ') {
- do_tab= 1;
- for (i=0; i<*charp; i++)
- if ((*linep)->line[i]!= ' ') {
- do_tab= 0;
- break;
- }
- }
-
- if (do_tab) {
- int tabsize= (*charp) % TXT_TABSIZE + 1;
- for (i=*charp+1; (*linep)->line[i]==' ' && tabsize<TXT_TABSIZE; i++)
- tabsize++;
- (*charp)= i;
- }
- else (*charp)+= BLI_str_utf8_size((*linep)->line + *charp);
- }
-
- undoing= oundoing;
- if (!undoing) txt_undo_add_op(text, sel?UNDO_SRIGHT:UNDO_CRIGHT);
- if (!sel) txt_pop_sel(text);
- }
- void txt_jump_left(Text *text, short sel)
- {
- TextLine **linep;
- int *charp, oldc;
-
- if (!text) return;
- if (sel) txt_curs_sel(text, &linep, &charp);
- else { txt_pop_first(text); txt_curs_cur(text, &linep, &charp); }
- if (!*linep) return;
- oldc = *charp;
- BLI_str_cursor_step_utf8((*linep)->line, (*linep)->len,
- charp, STRCUR_DIR_PREV,
- STRCUR_JUMP_DELIM);
-
- if (!sel) txt_pop_sel(text);
- if (!undoing) {
- int span = txt_get_span(text->lines.first, *linep);
- txt_undo_add_toop(text, sel ? UNDO_STO : UNDO_CTO, span, oldc, span, (unsigned short)*charp);
- }
- }
- void txt_jump_right(Text *text, short sel)
- {
- TextLine **linep;
- int *charp, oldc;
-
- if (!text) return;
- if (sel) txt_curs_sel(text, &linep, &charp);
- else { txt_pop_last(text); txt_curs_cur(text, &linep, &charp); }
- if (!*linep) return;
- oldc = *charp;
-
- BLI_str_cursor_step_utf8((*linep)->line, (*linep)->len,
- charp, STRCUR_DIR_NEXT,
- STRCUR_JUMP_DELIM);
-
- if (!sel) txt_pop_sel(text);
- if (!undoing) {
- int span = txt_get_span(text->lines.first, *linep);
- txt_undo_add_toop(text, sel ? UNDO_STO : UNDO_CTO, span, oldc, span, (unsigned short)*charp);
- }
- }
- void txt_move_bol (Text *text, short sel)
- {
- TextLine **linep;
- int *charp, old;
-
- if (!text) return;
- if (sel) txt_curs_sel(text, &linep, &charp);
- else txt_curs_cur(text, &linep, &charp);
- if (!*linep) return;
- old= *charp;
-
- *charp= 0;
- if (!sel) txt_pop_sel(text);
- 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);
- }
- void txt_move_eol (Text *text, short sel)
- {
- TextLine **linep;
- int *charp, old;
-
- if (!text) return;
- if (sel) txt_curs_sel(text, &linep, &charp);
- else txt_curs_cur(text, &linep, &charp);
- if (!*linep) return;
- old= *charp;
-
- *charp= (*linep)->len;
- if (!sel) txt_pop_sel(text);
- 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);
- }
- void txt_move_bof (Text *text, short sel)
- {
- TextLine **linep;
- int *charp, old;
-
- if (!text) return;
- if (sel) txt_curs_sel(text, &linep, &charp);
- else txt_curs_cur(text, &linep, &charp);
- if (!*linep) return;
- old= *charp;
- *linep= text->lines.first;
- *charp= 0;
- if (!sel) txt_pop_sel(text);
- 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);
- }
- void txt_move_eof (Text *text, short sel)
- {
- TextLine **linep;
- int *charp, old;
-
- if (!text) return;
- if (sel) txt_curs_sel(text, &linep, &charp);
- else txt_curs_cur(text, &linep, &charp);
- if (!*linep) return;
- old= *charp;
- *linep= text->lines.last;
- *charp= (*linep)->len;
- if (!sel) txt_pop_sel(text);
- 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);
- }
- void txt_move_toline (Text *text, unsigned int line, short sel)
- {
- txt_move_to(text, line, 0, sel);
- }
- /* Moves to a certain byte in a line, not a certain utf8-character! */
- void txt_move_to (Text *text, unsigned int line, unsigned int ch, short sel)
- {
- TextLine **linep, *oldl;
- int *charp, oldc;
- unsigned int i;
-
- if (!text) return;
- if (sel) txt_curs_sel(text, &linep, &charp);
- else txt_curs_cur(text, &linep, &charp);
- if (!*linep) return;
- oldc= *charp;
- oldl= *linep;
-
- *linep= text->lines.first;
- for (i=0; i<line; i++) {
- if ((*linep)->next) *linep= (*linep)->next;
- else break;
- }
- if (ch>(unsigned int)((*linep)->len))
- ch= (unsigned int)((*linep)->len);
- *charp= ch;
-
- if (!sel) txt_pop_sel(text);
- 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);
- }
- /****************************/
- /* Text selection functions */
- /****************************/
- static void txt_curs_swap (Text *text)
- {
- TextLine *tmpl;
- int tmpc;
-
- tmpl= text->curl;
- text->curl= text->sell;
- text->sell= tmpl;
-
- tmpc= text->curc;
- text->curc= text->selc;
- text->selc= tmpc;
-
- if (!undoing) txt_undo_add_op(text, UNDO_SWAP);
- }
- static void txt_pop_first (Text *text)
- {
-
- if (txt_get_span(text->curl, text->sell)<0 ||
- (text->curl==text->sell && text->curc>text->selc)) {
- txt_curs_swap(text);
- }
- if (!undoing) txt_undo_add_toop(text, UNDO_STO,
- txt_get_span(text->lines.first, text->sell),
- text->selc,
- txt_get_span(text->lines.first, text->curl),
- text->curc);
-
- txt_pop_sel(text);
- }
- static void txt_pop_last (Text *text)
- {
- if (txt_get_span(text->curl, text->sell)>0 ||
- (text->curl==text->sell && text->curc<text->selc)) {
- txt_curs_swap(text);
- }
- if (!undoing) txt_undo_add_toop(text, UNDO_STO,
- txt_get_span(text->lines.first, text->sell),
- text->selc,
- txt_get_span(text->lines.first, text->curl),
- text->curc);
-
- txt_pop_sel(text);
- }
- /* never used: CVS 1.19 */
- /* static void txt_pop_selr (Text *text) */
- void txt_pop_sel (Text *text)
- {
- text->sell= text->curl;
- text->selc= text->curc;
- }
- void txt_order_cursors(Text *text)
- {
- if (!text) return;
- if (!text->curl) return;
- if (!text->sell) return;
-
- /* Flip so text->curl is before text->sell */
- if (txt_get_span(text->curl, text->sell)<0 ||
- (text->curl==text->sell && text->curc>text->selc))
- txt_curs_swap(text);
- }
- int txt_has_sel(Text *text)
- {
- return ((text->curl!=text->sell) || (text->curc!=text->selc));
- }
- static void txt_delete_sel (Text *text)
- {
- TextLine *tmpl;
- TextMarker *mrk;
- char *buf;
- int move, lineno;
-
- if (!text) return;
- if (!text->curl) return;
- if (!text->sell) return;
- if (!txt_has_sel(text)) return;
-
- txt_order_cursors(text);
- if (!undoing) {
- buf= txt_sel_to_buf(text);
- txt_undo_add_block(text, UNDO_DBLOCK, buf);
- MEM_freeN(buf);
- }
- buf= MEM_mallocN(text->curc+(text->sell->len - text->selc)+1, "textline_string");
-
- if (text->curl != text->sell) {
- txt_clear_marker_region(text, text->curl, text->curc, text->curl->len, 0, 0);
- move= txt_get_span(text->curl, text->sell);
- }
- else {
- mrk= txt_find_marker_region(text, text->curl, text->curc, text->selc, 0, 0);
- if (mrk && (mrk->start > text->curc || mrk->end < text->selc))
- txt_clear_marker_region(text, text->curl, text->curc, text->selc, 0, 0);
- move= 0;
- }
- mrk= txt_find_marker_region(text, text->sell, text->selc-1, text->sell->len, 0, 0);
- if (mrk) {
- lineno= mrk->lineno;
- do {
- mrk->lineno -= move;
- if (mrk->start > text->curc) mrk->start -= text->selc - text->curc;
- mrk->end -= text->selc - text->curc;
- mrk= mrk->next;
- } while (mrk && mrk->lineno==lineno);
- }
- strncpy(buf, text->curl->line, text->curc);
- strcpy(buf+text->curc, text->sell->line + text->selc);
- buf[text->curc+(text->sell->len - text->selc)]=0;
- make_new_line(text->curl, buf);
-
- tmpl= text->sell;
- while (tmpl != text->curl) {
- tmpl= tmpl->prev;
- if (!tmpl) break;
-
- txt_delete_line(text, tmpl->next);
- }
-
- text->sell= text->curl;
- text->selc= text->curc;
- }
- void txt_sel_all (Text *text)
- {
- if (!text) return;
- text->curl= text->lines.first;
- text->curc= 0;
-
- text->sell= text->lines.last;
- text->selc= text->sell->len;
- }
- void txt_sel_line (Text *text)
- {
- if (!text) return;
- if (!text->curl) return;
-
- text->curc= 0;
- text->sell= text->curl;
- text->selc= text->sell->len;
- }
- /***************************/
- /* Cut and paste functions */
- /***************************/
- char *txt_to_buf (Text *text)
- {
- int length;
- TextLine *tmp, *linef, *linel;
- int charf, charl;
- char *buf;
-
- if (!text) return NULL;
- if (!text->curl) return NULL;
- if (!text->sell) return NULL;
- if (!text->lines.first) return NULL;
- linef= text->lines.first;
- charf= 0;
-
- linel= text->lines.last;
- charl= linel->len;
- if (linef == text->lines.last) {
- length= charl-charf;
- buf= MEM_mallocN(length+2, "text buffer");
-
- BLI_strncpy(buf, linef->line + charf, length+1);
- buf[length]=0;
- }
- else {
- length= linef->len - charf;
- length+= charl;
- length+= 2; /* For the 2 '\n' */
-
- tmp= linef->next;
- while (tmp && tmp!= linel) {
- length+= tmp->len+1;
- tmp= tmp->next;
- }
-
- buf= MEM_mallocN(length+1, "cut buffer");
- strncpy(buf, linef->line + charf, linef->len-charf);
- length= linef->len - charf;
-
- buf[length++]='\n';
-
- tmp= linef->next;
- while (tmp && tmp!=linel) {
- strncpy(buf+length, tmp->line, tmp->len);
- length+= tmp->len;
-
- buf[length++]='\n';
-
- tmp= tmp->next;
- }
- strncpy(buf+length, linel->line, charl);
- length+= charl;
-
- /* python compiler wants an empty end line */
- buf[length++]='\n';
- buf[length]=0;
- }
-
- return buf;
- }
- int txt_find_string(Text *text, const char *findstr, int wrap, int match_case)
- {
- TextLine *tl, *startl;
- char *s= NULL;
- if (!text || !text->curl || !text->sell) return 0;
-
- txt_order_cursors(text);
- tl= startl= text->sell;
-
- if (match_case) s= strstr(&tl->line[text->selc], findstr);
- else s= BLI_strcasestr(&tl->line[text->selc], findstr);
- while (!s) {
- tl= tl->next;
- if (!tl) {
- if (wrap)
- tl= text->lines.first;
- else
- break;
- }
- if (match_case) s= strstr(tl->line, findstr);
- else s= BLI_strcasestr(tl->line, findstr);
- if (tl==startl)
- break;
- }
-
- if (s) {
- int newl= txt_get_span(text->lines.first, tl);
- int newc= (int)(s-tl->line);
- txt_move_to(text, newl, newc, 0);
- txt_move_to(text, newl, newc + strlen(findstr), 1);
- return 1;
- }
- else
- return 0;
- }
- char *txt_sel_to_buf (Text *text)
- {
- char *buf;
- int length=0;
- TextLine *tmp, *linef, *linel;
- int charf, charl;
-
- if (!text) return NULL;
- if (!text->curl) return NULL;
- if (!text->sell) return NULL;
-
- if (text->curl==text->sell) {
- linef= linel= text->curl;
-
- if (text->curc < text->selc) {
- charf= text->curc;
- charl= text->selc;
- }
- else {
- charf= text->selc;
- charl= text->curc;
- }
- }
- else if (txt_get_span(text->curl, text->sell)<0) {
- linef= text->sell;
- linel= text->curl;
- charf= text->selc;
- charl= text->curc;
- }
- else {
- linef= text->curl;
- linel= text->sell;
-
- charf= text->curc;
- charl= text->selc;
- }
- if (linef == linel) {
- length= charl-charf;
- buf= MEM_mallocN(length+1, "sel buffer");
-
- BLI_strncpy(buf, linef->line + charf, length+1);
- }
- else {
- length+= linef->len - charf;
- length+= charl;
- length++; /* For the '\n' */
-
- tmp= linef->next;
- while (tmp && tmp!= linel) {
- length+= tmp->len+1;
- tmp= tmp->next;
- }
-
- buf= MEM_mallocN(length+1, "sel buffer");
-
- strncpy(buf, linef->line+ charf, linef->len-charf);
- length= linef->len-charf;
-
- buf[length++]='\n';
-
- tmp= linef->next;
- while (tmp && tmp!=linel) {
- strncpy(buf+length, tmp->line, tmp->len);
- length+= tmp->len;
-
- buf[length++]='\n';
-
- tmp= tmp->next;
- }
- strncpy(buf+length, linel->line, charl);
- length+= charl;
-
- buf[length]=0;
- }
- return buf;
- }
- static void txt_shift_markers(Text *text, int lineno, int count)
- {
- TextMarker *marker;
- for (marker=text->markers.first; marker; marker= marker->next)
- if (marker->lineno>=lineno) {
- marker->lineno+= count;
- }
- }
- void txt_insert_buf(Text *text, const char *in_buffer)
- {
- int l=0, u, len, lineno= -1, count= 0;
- size_t i=0, j;
- TextLine *add;
- char *buffer;
- if (!text) return;
- if (!in_buffer) return;
- txt_delete_sel(text);
-
- len= strlen(in_buffer);
- buffer= BLI_strdupn(in_buffer, len);
- len+= txt_extended_ascii_as_utf8(&buffer);
-
- if (!undoing) txt_undo_add_block(text, UNDO_IBLOCK, buffer);
- u= undoing;
- undoing= 1;
- /* Read the first line (or as close as possible */
- while (buffer[i] && buffer[i]!='\n')
- txt_add_raw_char(text, BLI_str_utf8_as_unicode_step(buffer, &i));
-
- if (buffer[i]=='\n') txt_split_curline(text);
- else { undoing = u; MEM_freeN(buffer); return; }
- i++;
- /* Read as many full lines as we can */
- lineno= txt_get_span(text->lines.first, text->curl);
- while (i<len) {
- l=0;
- while (buffer[i] && buffer[i]!='\n') {
- i++; l++;
- }
-
- if (buffer[i]=='\n') {
- add= txt_new_linen(buffer +(i-l), l);
- BLI_insertlinkbefore(&text->lines, text->curl, add);
- i++;
- count++;
- }
- else {
- if (count) {
- txt_shift_markers(text, lineno, count);
- count= 0;
- }
- for (j= i-l; j<i && j<len; )
- txt_add_raw_char(text, BLI_str_utf8_as_unicode_step(buffer, &j));
- break;
- }
- }
-
- MEM_freeN(buffer);
- if (count) {
- txt_shift_markers(text, lineno, count);
- }
- undoing= u;
- }
- /******************/
- /* Undo functions */
- /******************/
- static int max_undo_test(Text *text, int x)
- {
- while (text->undo_pos+x >= text->undo_len) {
- if (text->undo_len*2 > TXT_MAX_UNDO) {
- /* XXX error("Undo limit reached, buffer cleared\n"); */
- MEM_freeN(text->undo_buf);
- init_undo_text(text);
- return 0;
- }
- else {
- void *tmp= text->undo_buf;
- text->undo_buf= MEM_callocN(text->undo_len*2, "undo buf");
- memcpy(text->undo_buf, tmp, text->undo_len);
- text->undo_len*=2;
- MEM_freeN(tmp);
- }
- }
- return 1;
- }
- static void dump_buffer(Text *text)
- {
- int i= 0;
-
- while (i++<text->undo_pos) printf("%d: %d %c\n", i, text->undo_buf[i], text->undo_buf[i]);
- }
- void txt_print_undo(Text *text)
- {
- int i= 0;
- int op;
- const char *ops;
- int linep, charp;
-
- dump_buffer(text);
-
- printf ("---< Undo Buffer >---\n");
-
- printf ("UndoPosition is %d\n", text->undo_pos);
-
- while (i<=text->undo_pos) {
- op= text->undo_buf[i];
-
- if (op==UNDO_CLEFT) {
- ops= "Cursor left";
- }
- else if (op==UNDO_CRIGHT) {
- ops= "Cursor right";
- }
- else if (op==UNDO_CUP) {
- ops= "Cursor up";
- }
- else if (op==UNDO_CDOWN) {
- ops= "Cursor down";
- }
- else if (op==UNDO_SLEFT) {
- ops= "Selection left";
- }
- else if (op==UNDO_SRIGHT) {
- ops= "Selection right";
- }
- else if (op==UNDO_SUP) {
- ops= "Selection up";
- }
- else if (op==UNDO_SDOWN) {
- ops= "Selection down";
- }
- else if (op==UNDO_STO) {
- ops= "Selection ";
- }
- else if (op==UNDO_CTO) {
- ops= "Cursor ";
- }
- else if (op==UNDO_INSERT_1) {
- ops= "Insert ascii ";
- }
- else if (op==UNDO_INSERT_2) {
- ops= "Insert 2 bytes ";
- }
- else if (op==UNDO_INSERT_3) {
- ops= "Insert 3 bytes ";
- }
- else if (op==UNDO_INSERT_4) {
- ops= "Insert unicode ";
- }
- else if (op==UNDO_BS_1) {
- ops= "Backspace for ascii ";
- }
- else if (op==UNDO_BS_2) {
- ops= "Backspace for 2 bytes ";
- }
- else if (op==UNDO_BS_3) {
- ops= "Backspace for 3 bytes ";
- }
- else if (op==UNDO_BS_4) {
- ops= "Backspace for unicode ";
- }
- else if (op==UNDO_DEL_1) {
- ops= "Delete ascii ";
- }
- else if (op==UNDO_DEL_2) {
- ops= "Delete 2 bytes ";
- }
- else if (op==UNDO_DEL_3) {
- ops= "Delete 3 bytes ";
- }
- else if (op==UNDO_DEL_4) {
- ops= "Delete unicode ";
- }
- else if (op==UNDO_SWAP) {
- ops= "Cursor swap";
- }
- else if (op==UNDO_DBLOCK) {
- ops= "Delete text block";
- }
- else if (op==UNDO_IBLOCK) {
- ops= "Insert text block";
- }
- else if (op==UNDO_INDENT) {
- ops= "Indent ";
- }
- else if (op==UNDO_UNINDENT) {
- ops= "Unindent ";
- }
- else if (op==UNDO_COMMENT) {
- ops= "Comment ";
- }
- else if (op==UNDO_UNCOMMENT) {
- ops= "Uncomment ";
- }
- else {
- ops= "Unknown";
- }
-
- printf ("Op (%o) at %d = %s", op, i, ops);
- if (op >= UNDO_INSERT_1 && op <= UNDO_DEL_4) {
- i++;
- printf (" - Char is ");
- switch (op) {
- case UNDO_INSERT_1: case UNDO_BS_1: case UNDO_DEL_1:
- printf ("%c", text->undo_buf[i]);
- i++;
- break;
- case UNDO_INSERT_2: case UNDO_BS_2: case UNDO_DEL_2:
- printf ("%c%c", text->undo_buf[i], text->undo_buf[i+1]);
- i+=2;
- break;
- case UNDO_INSERT_3: case UNDO_BS_3: case UNDO_DEL_3:
- printf ("%c%c%c", text->undo_buf[i], text->undo_buf[i+1], text->undo_buf[i+2]);
- i+=3;
- break;
- case UNDO_INSERT_4: case UNDO_BS_4: case UNDO_DEL_4: {
- unsigned int uc;
- char c[BLI_UTF8_MAX+1];
- size_t c_len;
- uc= text->undo_buf[i]; i++;
- uc= uc+(text->undo_buf[i]<<8); i++;
- uc= uc+(text->undo_buf[i]<<16); i++;
- uc= uc+(text->undo_buf[i]<<24); i++;
- c_len= BLI_str_utf8_from_unicode(uc, c);
- c[c_len]= '\0';
- puts(c);
- }
- }
- }
- else if (op==UNDO_STO || op==UNDO_CTO) {
- i++;
- charp= text->undo_buf[i]; i++;
- charp= charp+(text->undo_buf[i]<<8); i++;
- linep= text->undo_buf[i]; i++;
- linep= linep+(text->undo_buf[i]<<8); i++;
- linep= linep+(text->undo_buf[i]<<16); i++;
- linep= linep+(text->undo_buf[i]<<24); i++;
-
- printf ("to <%d, %d> ", linep, charp);
- charp= text->undo_buf[i]; i++;
- charp= charp+(text->undo_buf[i]<<8); i++;
- linep= text->undo_buf[i]; i++;
- linep= linep+(text->undo_buf[i]<<8); i++;
- linep= linep+(text->undo_buf[i]<<16); i++;
- linep= linep+(text->undo_buf[i]<<24); i++;
-
- printf ("from <%d, %d>", linep, charp);
- }
- else if (op==UNDO_DBLOCK || op==UNDO_IBLOCK) {
- i++;
- linep= text->undo_buf[i]; i++;
- linep= linep+(text->undo_buf[i]<<8); i++;
- linep= linep+(text->undo_buf[i]<<16); i++;
- linep= linep+(text->undo_buf[i]<<24); i++;
-
- printf (" (length %d) <", linep);
-
- while (linep>0) {
- putchar(text->undo_buf[i]);
- linep--; i++;
- }
-
- linep= text->undo_buf[i]; i++;
- linep= linep+(text->undo_buf[i]<<8); i++;
- linep= linep+(text->undo_buf[i]<<16); i++;
- linep= linep+(text->undo_buf[i]<<24); i++;
- printf ("> (%d)", linep);
- }
- else if (op==UNDO_INDENT || op==UNDO_UNINDENT) {
- i++;
- charp= text->undo_buf[i]; i++;
- charp= charp+(text->undo_buf[i]<<8); i++;
- linep= text->undo_buf[i]; i++;
- linep= linep+(text->undo_buf[i]<<8); i++;
- linep= linep+(text->undo_buf[i]<<16); i++;
- linep= linep+(text->undo_buf[i]<<24); i++;
-
- printf ("to <%d, %d> ", linep, charp);
- charp= text->undo_buf[i]; i++;
- charp= charp+(text->undo_buf[i]<<8); i++;
- linep= text->undo_buf[i]; i++;
- linep= linep+(text->undo_buf[i]<<8); i++;
- linep= linep+(text->undo_buf[i]<<16); i++;
- linep= linep+(text->undo_buf[i]<<24); i++;
-
- printf ("from <%d, %d>", linep, charp);
- }
-
- printf (" %d\n", i);
- i++;
- }
- }
- static void txt_undo_add_op(Text *text, int op)
- {
- if (!max_undo_test(text, 2))
- return;
-
- text->undo_pos++;
- text->undo_buf[text->undo_pos]= op;
- text->undo_buf[text->undo_pos+1]= 0;
- }
- static void txt_undo_store_uint16(char *undo_buf, int *undo_pos, unsigned short value)
- {
- undo_buf[*undo_pos]= (value)&0xff;
- (*undo_pos)++;
- undo_buf[*undo_pos]= (value>>8)&0xff;
- (*undo_pos)++;
- }
- static void txt_undo_store_uint32(char *undo_buf, int *undo_pos, unsigned int value)
- {
- undo_buf[*undo_pos]= (value)&0xff;
- (*undo_pos)++;
- undo_buf[*undo_pos]= (value>>8)&0xff;
- (*undo_pos)++;
- undo_buf[*undo_pos]= (value>>16)&0xff;
- (*undo_pos)++;
- undo_buf[*undo_pos]= (value>>24)&0xff;
- (*undo_pos)++;
- }
- static void txt_undo_add_block(Text *text, int op, const char *buf)
- {
- unsigned int length= strlen(buf);
-
- if (!max_undo_test(text, length+11))
- return;
- text->undo_pos++;
- text->undo_buf[text->undo_pos]= op;
- text->undo_pos++;
-
- txt_undo_store_uint32(text->undo_buf, &text->undo_pos, length);
-
- strncpy(text->undo_buf+text->undo_pos, buf, length);
- text->undo_pos+=length;
- txt_undo_store_uint32(text->undo_buf, &text->undo_pos, length);
- text->undo_buf[text->undo_pos]= op;
-
- text->undo_buf[text->undo_pos+1]= 0;
- }
- void txt_undo_add_toop(Text *text, int op, unsigned int froml, unsigned short fromc, unsigned int tol, unsigned short toc)
- {
- if (!max_undo_test(text, 15))
- return;
- if (froml==tol && fromc==toc) return;
- text->undo_pos++;
- text->undo_buf[text->undo_pos]= op;
- text->undo_pos++;
-
- txt_undo_store_uint16(text->undo_buf, &text->undo_pos, fromc);
- txt_undo_store_uint32(text->undo_buf, &text->undo_pos, froml);
- txt_undo_store_uint16(text->undo_buf, &text->undo_pos, toc);
- txt_undo_store_uint32(text->undo_buf, &text->undo_pos, tol);
-
- text->undo_buf[text->undo_pos]= op;
- text->undo_buf[text->undo_pos+1]= 0;
- }
- static void txt_undo_add_charop(Text *text, int op_start, unsigned int c)
- {
- char utf8[BLI_UTF8_MAX];
- size_t i, utf8_size = BLI_str_utf8_from_unicode(c, utf8);
-
- if (!max_undo_test(text, 3 + utf8_size))
- return;
-
- text->undo_pos++;
-
- if (utf8_size < 4) {
- text->undo_buf[text->undo_pos]= op_start + utf8_size - 1;
- text->undo_pos++;
-
- for (i = 0; i < utf8_size; i++) {
- text->undo_buf[text->undo_pos]= utf8[i];
- text->undo_pos++;
- }
-
- text->undo_buf[text->undo_pos]= op_start + utf8_size - 1;
- }
- else {
- text->undo_buf[text->undo_pos]= op_start + 3;
- text->undo_pos++;
- txt_undo_store_uint32(text->undo_buf, &text->undo_pos, c);
- text->undo_buf[text->undo_pos]= op_start + 3;
- }
-
- text->undo_buf[text->undo_pos+1]= 0;
- }
- static unsigned short txt_undo_read_uint16(const char *undo_buf, int *undo_pos)
- {
- unsigned short val;
- val= undo_buf[*undo_pos]; (*undo_pos)--;
- val= (val<<8)+undo_buf[*undo_pos]; (*undo_pos)--;
- return val;
- }
- static unsigned int txt_undo_read_uint32(const char *undo_buf, int *undo_pos)
- {
- unsigned int val;
- val= undo_buf[*undo_pos]; (*undo_pos)--;
- val= (val<<8)+undo_buf[*undo_pos]; (*undo_pos)--;
- val= (val<<8)+undo_buf[*undo_pos]; (*undo_pos)--;
- val= (val<<8)+undo_buf[*undo_pos]; (*undo_pos)--;
- return val;
- }
- static unsigned int txt_undo_read_unicode(const char *undo_buf, int *undo_pos, short bytes)
- {
- unsigned int unicode;
- char utf8[BLI_UTF8_MAX+1];
-
- switch (bytes) {
- case 1: /* ascii */
- unicode = undo_buf[*undo_pos]; (*undo_pos)--;
- break;
- case 2: /* 2-byte symbol */
- utf8[2] = '\0';
- utf8[1] = undo_buf[*undo_pos]; (*undo_pos)--;
- utf8[0] = undo_buf[*undo_pos]; (*undo_pos)--;
- unicode= BLI_str_utf8_as_unicode(utf8);
- break;
- case 3: /* 3-byte symbol */
- utf8[3] = '\0';
- utf8[2] = undo_buf[*undo_pos]; (*undo_pos)--;
- utf8[1] = undo_buf[*undo_pos]; (*undo_pos)--;
- utf8[0] = undo_buf[*undo_pos]; (*undo_pos)--;
- unicode= BLI_str_utf8_as_unicode(utf8);
- break;
- case 4: /* 32-bit unicode symbol */
- unicode= txt_undo_read_uint32(undo_buf, undo_pos);
- default:
- /* should never happen */
- BLI_assert(0);
- unicode= 0;
- }
-
- return unicode;
- }
- static unsigned short txt_redo_read_uint16(const char *undo_buf, int *undo_pos)
- {
- unsigned short val;
- val = undo_buf[*undo_pos]; (*undo_pos)++;
- val = val+(undo_buf[*undo_pos]<<8); (*undo_pos)++;
- return val;
- }
- static unsigned int txt_redo_read_uint32(const char *undo_buf, int *undo_pos)
- {
- unsigned int val;
- val= undo_buf[*undo_pos]; (*undo_pos)++;
- val= val+(undo_buf[*undo_pos]<<8); (*undo_pos)++;
- val= val+(undo_buf[*undo_pos]<<16); (*undo_pos)++;
- val= val+(undo_buf[*undo_pos]<<24); (*undo_pos)++;
- return val;
- }
- static unsigned int txt_redo_read_unicode(const char *undo_buf, int *undo_pos, short bytes)
- {
- unsigned int unicode;
- char utf8[BLI_UTF8_MAX+1];
-
- switch (bytes) {
- case 1: /* ascii */
- unicode = undo_buf[*undo_pos]; (*undo_pos)++;
- break;
- case 2: /* 2-byte symbol */
- utf8[0] = undo_buf[*undo_pos]; (*undo_pos)++;
- utf8[1] = undo_buf[*undo_pos]; (*undo_pos)++;
- utf8[2] = '\0';
- unicode= BLI_str_utf8_as_unicode(utf8);
- break;
- case 3: /* 3-byte symbol */
- utf8[0] = undo_buf[*undo_pos]; (*undo_pos)++;
- utf8[1] = undo_buf[*undo_pos]; (*undo_pos)++;
- utf8[2] = undo_buf[*undo_pos]; (*undo_pos)++;
- utf8[3] = '\0';
- unicode= BLI_str_utf8_as_unicode(utf8);
- break;
- case 4: /* 32-bit unicode symbol */
- unicode= txt_undo_read_uint32(undo_buf, undo_pos);
- default:
- /* should never happen */
- BLI_assert(0);
- unicode= 0;
- }
-
- return unicode;
- }
- void txt_do_undo(Text *text)
- {
- int op= text->undo_buf[text->undo_pos];
- unsigned int linep, i;
- unsigned short charp;
- TextLine *holdl;
- int holdc, holdln;
- char *buf;
-
- if (text->undo_pos<0) {
- return;
- }
- text->undo_pos--;
- undoing= 1;
-
- switch(op) {
- case UNDO_CLEFT:
- txt_move_right(text, 0);
- break;
-
- case UNDO_CRIGHT:
- txt_move_left(text, 0);
- break;
-
- case UNDO_CUP:
- txt_move_down(text, 0);
- break;
-
- case UNDO_CDOWN:
- txt_move_up(text, 0);
- break;
- case UNDO_SLEFT:
- txt_move_right(text, 1);
- break;
- case UNDO_SRIGHT:
- txt_move_left(text, 1);
- break;
- case UNDO_SUP:
- txt_move_down(text, 1);
- break;
- case UNDO_SDOWN:
- txt_move_up(text, 1);
- break;
-
- case UNDO_CTO:
- case UNDO_STO:
- text->undo_pos--;
- text->undo_pos--;
- text->undo_pos--;
- text->undo_pos--;
-
- text->undo_pos--;
- text->undo_pos--;
-
- linep= txt_undo_read_uint32(text->undo_buf, &text->undo_pos);
- charp= txt_undo_read_uint16(text->undo_buf, &text->undo_pos);
-
- if (op==UNDO_CTO) {
- txt_move_toline(text, linep, 0);
- text->curc= charp;
- txt_pop_sel(text);
- }
- else {
- txt_move_toline(text, linep, 1);
- text->selc= charp;
- }
-
- text->undo_pos--;
- break;
-
- case UNDO_INSERT_1: case UNDO_INSERT_2: case UNDO_INSERT_3: case UNDO_INSERT_4:
- txt_backspace_char(text);
- text->undo_pos-= op - UNDO_INSERT_1 + 1;
- text->undo_pos--;
- break;
- case UNDO_BS_1: case UNDO_BS_2: case UNDO_BS_3: case UNDO_BS_4:
- charp = op - UNDO_BS_1 + 1;
- txt_add_char(text, txt_undo_read_unicode(text->undo_buf, &text->undo_pos, charp));
- text->undo_pos--;
- break;
-
- case UNDO_DEL_1: case UNDO_DEL_2: case UNDO_DEL_3: case UNDO_DEL_4:
- charp = op - UNDO_DEL_1 + 1;
- txt_add_char(text, txt_undo_read_unicode(text->undo_buf, &text->undo_pos, charp));
- txt_move_left(text, 0);
- text->undo_pos--;
- break;
- case UNDO_SWAP:
- txt_curs_swap(text);
- break;
- case UNDO_DBLOCK:
- linep= txt_undo_read_uint32(text->undo_buf, &text->undo_pos);
- buf= MEM_mallocN(linep+1, "dblock buffer");
- for (i=0; i < linep; i++) {
- buf[(linep-1)-i]= text->undo_buf[text->undo_pos];
- text->undo_pos--;
- }
- buf[i]= 0;
-
- txt_curs_first(text, &holdl, &holdc);
- holdln= txt_get_span(text->lines.first, holdl);
-
- txt_insert_buf(text, buf);
- MEM_freeN(buf);
- text->curl= text->lines.first;
- while (holdln>0) {
- if (text->curl->next)
- text->curl= text->curl->next;
-
- holdln--;
- }
- text->curc= holdc;
- text->undo_pos--;
- text->undo_pos--;
- text->undo_pos--;
- text->undo_pos--;
- text->undo_pos--;
-
- break;
- case UNDO_IBLOCK:
- linep= txt_undo_read_uint32(text->undo_buf, &text->undo_pos);
- txt_delete_sel(text);
- /* txt_backspace_char removes utf8-characters, not bytes */
- buf= MEM_mallocN(linep+1, "iblock buffer");
- for (i=0; i < linep; i++) {
- buf[(linep-1)-i]= text->undo_buf[text->undo_pos];
- text->undo_pos--;
- }
- buf[i]= 0;
- linep= txt_utf8_len(buf);
- MEM_freeN(buf);
- while (linep>0) {
- txt_backspace_char(text);
- linep--;
- }
- text->undo_pos--;
- text->undo_pos--;
- text->undo_pos--;
- text->undo_pos--;
-
- text->undo_pos--;
- break;
- case UNDO_INDENT:
- case UNDO_UNINDENT:
- case UNDO_COMMENT:
- case UNDO_UNCOMMENT:
- linep= txt_undo_read_uint32(text->undo_buf, &text->undo_pos);
- //linep is now the end line of the selection
-
- charp = txt_undo_read_uint16(text->undo_buf, &text->undo_pos);
- //charp is the last char selected or text->line->len
-
- //set the selection for this now
- text->selc = charp;
- text->sell = text->lines.first;
- for (i= 0; i < linep; i++) {
- text->sell = text->sell->next;
- }
- linep= txt_undo_read_uint32(text->undo_buf, &text->undo_pos);
- //first line to be selected
-
- charp = txt_undo_read_uint16(text->undo_buf, &text->undo_pos);
- //first postion to be selected
- text->curc = charp;
- text->curl = text->lines.first;
- for (i = 0; i < linep; i++) {
- text->curl = text->curl->next;
- }
-
- if (op==UNDO_INDENT) {
- txt_unindent(text);
- }
- else if (op== UNDO_UNINDENT) {
- txt_indent(text);
- }
- else if (op == UNDO_COMMENT) {
- txt_uncomment(text);
- }
- else if (op == UNDO_UNCOMMENT) {
- txt_comment(text);
- }
- text->undo_pos--;
- break;
- default:
- //XXX error("Undo buffer error - resetting");
- text->undo_pos= -1;
-
- break;
- }
- /* next undo step may need evaluating */
- if (text->undo_pos>=0) {
- switch (text->undo_buf[text->undo_pos]) {
- case UNDO_STO:
- txt_do_undo(text);
- txt_do_redo(text); /* selections need restoring */
- break;
- case UNDO_SWAP:
- txt_do_undo(text); /* swaps should appear transparent */
- break;
- }
- }
-
- undoing= 0;
- }
- void txt_do_redo(Text *text)
- {
- char op;
- unsigned int linep, i;
- unsigned short charp;
- char *buf;
-
- text->undo_pos++;
- op= text->undo_buf[text->undo_pos];
-
- if (!op) {
- text->undo_pos--;
- return;
- }
-
- undoing= 1;
- switch(op) {
- case UNDO_CLEFT:
- txt_move_left(text, 0);
- break;
-
- case UNDO_CRIGHT:
- txt_move_right(text, 0);
- break;
-
- case UNDO_CUP:
- txt_move_up(text, 0);
- break;
-
- case UNDO_CDOWN:
- txt_move_down(text, 0);
- break;
- case UNDO_SLEFT:
- txt_move_left(text, 1);
- break;
- case UNDO_SRIGHT:
- txt_move_right(text, 1);
- break;
- case UNDO_SUP:
- txt_move_up(text, 1);
- break;
- case UNDO_SDOWN:
- txt_move_down(text, 1);
- break;
-
- case UNDO_INSERT_1: case UNDO_INSERT_2: case UNDO_INSERT_3: case UNDO_INSERT_4:
- text->undo_pos++;
- charp = op - UNDO_INSERT_1 + 1;
- txt_add_char(text, txt_redo_read_unicode(text->undo_buf, &text->undo_pos, charp));
- break;
- case UNDO_BS_1: case UNDO_BS_2: case UNDO_BS_3: case UNDO_BS_4:
- text->undo_pos++;
- txt_backspace_char(text);
- text->undo_pos+= op - UNDO_BS_1 + 1;
- break;
- case UNDO_DEL_1: case UNDO_DEL_2: case UNDO_DEL_3: case UNDO_DEL_4:
- text->undo_pos++;
- txt_delete_char(text);
- text->undo_pos+= op - UNDO_DEL_1 + 1;
- break;
- case UNDO_SWAP:
- txt_curs_swap(text);
- txt_do_redo(text); /* swaps should appear transparent a*/
- break;
-
- case UNDO_CTO:
- case UNDO_STO:
- text->undo_pos++;
- text->undo_pos++;
- text->undo_pos++;
- text->undo_pos++;
- text->undo_pos++;
- text->undo_pos++;
- text->undo_pos++;
- charp= txt_redo_read_uint16(text->undo_buf, &text->undo_pos);
- linep= txt_redo_read_uint32(text->undo_buf, &text->undo_pos);
-
- if (op==UNDO_CTO) {
- txt_move_toline(text, linep, 0);
- text->curc= charp;
- txt_pop_sel(text);
- }
- else {
- txt_move_toline(text, linep, 1);
- text->selc= charp;
- }
- break;
- case UNDO_DBLOCK:
- text->undo_pos++;
- linep= txt_redo_read_uint32(text->undo_buf, &text->undo_pos);
- txt_delete_sel(text);
-
- text->undo_pos+=linep;
- text->undo_pos++;
- text->undo_pos++;
- text->undo_pos++;
- text->undo_pos++;
-
- break;
- case UNDO_IBLOCK:
- text->undo_pos++;
- linep= txt_redo_read_uint32(text->undo_buf, &text->undo_pos);
- buf= MEM_mallocN(linep+1, "iblock buffer");
- memcpy (buf, &text->undo_buf[text->undo_pos], linep);
- text->undo_pos+= linep;
- buf[linep]= 0;
-
- txt_insert_buf(text, buf);
- MEM_freeN(buf);
- text->undo_pos++;
- text->undo_pos++;
- text->undo_pos++;
- text->undo_pos++;
- break;
-
- case UNDO_INDENT:
- case UNDO_UNINDENT:
- case UNDO_COMMENT:
- case UNDO_UNCOMMENT:
- text->undo_pos++;
- charp = txt_redo_read_uint16(text->undo_buf, &text->undo_pos);
- //charp is the first char selected or 0
-
- linep= txt_redo_read_uint32(text->undo_buf, &text->undo_pos);
- //linep is now the first line of the selection
- //set the selcetion for this now
- text->curc = charp;
- text->curl = text->lines.first;
- for (i= 0; i < linep; i++) {
- text->curl = text->curl->next;
- }
-
- charp = txt_redo_read_uint16(text->undo_buf, &text->undo_pos);
- //last postion to be selected
-
- linep= txt_redo_read_uint32(text->undo_buf, &text->undo_pos);
- //Last line to be selected
-
- text->selc = charp;
- text->sell = text->lines.first;
- for (i = 0; i < linep; i++) {
- text->sell = text->sell->next;
- }
- if (op==UNDO_INDENT) {
- txt_indent(text);
- }
- else if (op== UNDO_UNINDENT) {
- txt_unindent(text);
- }
- else if (op == UNDO_COMMENT) {
- txt_comment(text);
- }
- else if (op == UNDO_UNCOMMENT) {
- txt_uncomment(text);
- }
- break;
- default:
- //XXX error("Undo buffer error - resetting");
- text->undo_pos= -1;
- break;
- }
-
- undoing= 0;
- }
- /**************************/
- /* Line editing functions */
- /**************************/
- void txt_split_curline (Text *text)
- {
- TextLine *ins;
- TextMarker *mrk;
- char *left, *right;
- int lineno= -1;
-
- if (!text) return;
- if (!text->curl) return;
- txt_delete_sel(text);
- /* Move markers */
- lineno= txt_get_span(text->lines.first, text->curl);
- mrk= text->markers.first;
- while (mrk) {
- if (mrk->lineno==lineno && mrk->start>text->curc) {
- mrk->lineno++;
- mrk->start -= text->curc;
- mrk->end -= text->curc;
- }
- else if (mrk->lineno > lineno) {
- mrk->lineno++;
- }
- mrk= mrk->next;
- }
- /* Make the two half strings */
- left= MEM_mallocN(text->curc+1, "textline_string");
- if (text->curc) memcpy(left, text->curl->line, text->curc);
- left[text->curc]=0;
-
- right= MEM_mallocN(text->curl->len - text->curc+1, "textline_string");
- memcpy(right, text->curl->line+text->curc, text->curl->len-text->curc+1);
- MEM_freeN(text->curl->line);
- if (text->curl->format) MEM_freeN(text->curl->format);
- /* Make the new TextLine */
-
- ins= MEM_mallocN(sizeof(TextLine), "textline");
- ins->line= left;
- ins->format= NULL;
- ins->len= text->curc;
-
- text->curl->line= right;
- text->curl->format= NULL;
- text->curl->len= text->curl->len - text->curc;
-
- BLI_insertlinkbefore(&text->lines, text->curl, ins);
-
- text->curc=0;
-
- txt_make_dirty(text);
- txt_clean_text(text);
-
- txt_pop_sel(text);
- if (!undoing) txt_undo_add_charop(text, UNDO_INSERT_1, '\n');
- }
- static void txt_delete_line (Text *text, TextLine *line)
- {
- TextMarker *mrk=NULL, *nxt;
- int lineno= -1;
- if (!text) return;
- if (!text->curl) return;
- lineno= txt_get_span(text->lines.first, line);
- mrk= text->markers.first;
- while (mrk) {
- nxt= mrk->next;
- if (mrk->lineno==lineno)
- BLI_freelinkN(&text->markers, mrk);
- else if (mrk->lineno > lineno)
- mrk->lineno--;
- mrk= nxt;
- }
- BLI_remlink (&text->lines, line);
-
- if (line->line) MEM_freeN(line->line);
- if (line->format) MEM_freeN(line->format);
- MEM_freeN(line);
- txt_make_dirty(text);
- txt_clean_text(text);
- }
- static void txt_combine_lines (Text *text, TextLine *linea, TextLine *lineb)
- {
- char *tmp;
- TextMarker *mrk= NULL;
- int lineno=-1;
-
- if (!text) return;
-
- if (!linea || !lineb) return;
- mrk= txt_find_marker_region(text, lineb, 0, lineb->len, 0, 0);
- if (mrk) {
- lineno= mrk->lineno;
- do {
- mrk->lineno--;
- mrk->start += linea->len;
- mrk->end += linea->len;
- mrk= mrk->next;
- } while (mrk && mrk->lineno==lineno);
- }
- if (lineno==-1) lineno= txt_get_span(text->lines.first, lineb);
-
- tmp= MEM_mallocN(linea->len+lineb->len+1, "textline_string");
-
- strcpy(tmp, linea->line);
- strcat(tmp, lineb->line);
- make_new_line(linea, tmp);
-
- txt_delete_line(text, lineb);
-
- txt_make_dirty(text);
- txt_clean_text(text);
- }
- void txt_delete_char(Text *text)
- {
- unsigned int c='\n';
-
- if (!text) return;
- if (!text->curl) return;
- if (txt_has_sel(text)) { /* deleting a selection */
- txt_delete_sel(text);
- txt_make_dirty(text);
- return;
- }
- else if (text->curc== text->curl->len) { /* Appending two lines */
- if (text->curl->next) {
- txt_combine_lines(text, text->curl, text->curl->next);
- txt_pop_sel(text);
- }
- else
- return;
- }
- else { /* Just deleting a char */
- size_t c_len = 0;
- TextMarker *mrk;
- c= BLI_str_utf8_as_unicode_and_size(text->curl->line + text->curc, &c_len);
- mrk= txt_find_marker_region(text, text->curl, text->curc - c_len, text->curl->len, 0, 0);
- if (mrk) {
- int lineno= mrk->lineno;
- if (mrk->end==text->curc) {
- if ((mrk->flags & TMARK_TEMP) && !(mrk->flags & TMARK_EDITALL)) {
- txt_clear_markers(text, mrk->group, TMARK_TEMP);
- }
- else {
- BLI_freelinkN(&text->markers, mrk);
- }
- return;
- }
- do {
- if (mrk->start>text->curc) mrk->start-= c_len;
- mrk->end-= c_len;
- mrk= mrk->next;
- } while (mrk && mrk->lineno==lineno);
- }
-
- memmove(text->curl->line+text->curc, text->curl->line+text->curc+c_len, text->curl->len-text->curc-c_len+1);
- text->curl->len-= c_len;
- txt_pop_sel(text);
- }
- txt_make_dirty(text);
- txt_clean_text(text);
-
- if (!undoing) txt_undo_add_charop(text, UNDO_DEL_1, c);
- }
- void txt_delete_word (Text *text)
- {
- txt_jump_right(text, 1);
- txt_delete_sel(text);
- }
- void txt_backspace_char (Text *text)
- {
- unsigned int c='\n';
-
- if (!text) return;
- if (!text->curl) return;
-
- if (txt_has_sel(text)) { /* deleting a selection */
- txt_delete_sel(text);
- txt_make_dirty(text);
- return;
- }
- else if (text->curc==0) { /* Appending two lines */
- if (!text->curl->prev) return;
-
- text->curl= text->curl->prev;
- text->curc= text->curl->len;
-
- txt_combine_lines(text, text->curl, text->curl->next);
- txt_pop_sel(text);
- }
- else { /* Just backspacing a char */
- size_t c_len = 0;
- TextMarker *mrk;
- char *prev = BLI_str_prev_char_utf8(text->curl->line + text->curc);
- c= BLI_str_utf8_as_unicode_and_size(prev, &c_len);
- mrk= txt_find_marker_region(text, text->curl, text->curc - c_len, text->curl->len, 0, 0);
- if (mrk) {
- int lineno= mrk->lineno;
- if (mrk->start==text->curc) {
- if ((mrk->flags & TMARK_TEMP) && !(mrk->flags & TMARK_EDITALL)) {
- txt_clear_markers(text, mrk->group, TMARK_TEMP);
- }
- else {
- BLI_freelinkN(&text->markers, mrk);
- }
- return;
- }
- do {
- if (mrk->start>text->curc - c_len) mrk->start-= c_len;
- mrk->end-= c_len;
- mrk= mrk->next;
- } while (mrk && mrk->lineno==lineno);
- }
-
- /* source and destination overlap, don't use memcpy() */
- memmove(text->curl->line + text->curc - c_len,
- text->curl->line + text->curc,
- text->curl->len - text->curc + 1);
- text->curl->len-= c_len;
- text->curc-= c_len;
- txt_pop_sel(text);
- }
- txt_make_dirty(text);
- txt_clean_text(text);
-
- if (!undoing) txt_undo_add_charop(text, UNDO_BS_1, c);
- }
- void txt_backspace_word (Text *text)
- {
- txt_jump_left(text, 1);
- txt_delete_sel(text);
- }
- /* Max spaces to replace a tab with, currently hardcoded to TXT_TABSIZE = 4.
- * Used by txt_convert_tab_to_spaces, indent and unindent.
- * Remember to change this string according to max tab size */
- static char tab_to_spaces[] = " ";
- static void txt_convert_tab_to_spaces (Text *text)
- {
- /* sb aims to pad adjust the tab-width needed so that the right number of spaces
- * is added so that the indention of the line is the right width (i.e. aligned
- * to multiples of TXT_TABSIZE)
- */
- char *sb = &tab_to_spaces[text->curc % TXT_TABSIZE];
- txt_insert_buf(text, sb);
- }
- static int txt_add_char_intern (Text *text, unsigned int add, int replace_tabs)
- {
- int lineno;
- char *tmp, ch[BLI_UTF8_MAX];
- TextMarker *mrk;
- size_t add_len;
-
- if (!text) return 0;
- if (!text->curl) return 0;
- if (add=='\n') {
- txt_split_curline(text);
- return 1;
- }
-
- /* insert spaces rather than tabs */
- if (add == '\t' && replace_tabs) {
- txt_convert_tab_to_spaces(text);
- return 1;
- }
- txt_delete_sel(text);
-
- add_len = BLI_str_utf8_from_unicode(add, ch);
- mrk= txt_find_marker_region(text, text->curl, text->curc-1, text->curl->len, 0, 0);
- if (mrk) {
- lineno= mrk->lineno;
- do {
- if (mrk->start>text->curc) mrk->start+= add_len;
- mrk->end+= add_len;
- mrk= mrk->next;
- } while (mrk && mrk->lineno==lineno);
- }
-
- tmp= MEM_mallocN(text->curl->len+add_len+1, "textline_string");
-
- memcpy(tmp, text->curl->line, text->curc);
- memcpy(tmp+text->curc, ch, add_len);
- memcpy(tmp+text->curc+add_len, text->curl->line+text->curc, text->curl->len-text->curc+1);
- make_new_line(text->curl, tmp);
-
- text->curc+= add_len;
- txt_pop_sel(text);
-
- txt_make_dirty(text);
- txt_clean_text(text);
- if (!undoing) txt_undo_add_charop(text, UNDO_INSERT_1, add);
- return 1;
- }
- int txt_add_char (Text *text, unsigned int add)
- {
- return txt_add_char_intern(text, add, text->flags & TXT_TABSTOSPACES);
- }
- int txt_add_raw_char (Text *text, unsigned int add)
- {
- return txt_add_char_intern(text, add, 0);
- }
- void txt_delete_selected(Text *text)
- {
- txt_delete_sel(text);
- txt_make_dirty(text);
- }
- int txt_replace_char (Text *text, unsigned int add)
- {
- unsigned int del;
- size_t del_size = 0, add_size;
- char ch[BLI_UTF8_MAX];
-
- if (!text) return 0;
- if (!text->curl) return 0;
- /* If text is selected or we're at the end of the line just use txt_add_char */
- if (text->curc==text->curl->len || txt_has_sel(text) || add=='\n') {
- int i= txt_add_char(text, add);
- TextMarker *mrk= txt_find_marker(text, text->curl, text->curc, 0, 0);
- if (mrk) BLI_freelinkN(&text->markers, mrk);
- return i;
- }
-
- del= BLI_str_utf8_as_unicode_and_size(text->curl->line + text->curc, &del_size);
- add_size= BLI_str_utf8_from_unicode(add, ch);
-
- if (add_size > del_size) {
- char *tmp= MEM_mallocN(text->curl->len+add_size-del_size+1, "textline_string");
- memcpy(tmp, text->curl->line, text->curc);
- memcpy(tmp+text->curc+add_size, text->curl->line+text->curc+del_size, text->curl->len-text->curc-del_size+1);
- MEM_freeN(text->curl->line);
- text->curl->line = tmp;
- }
- else if (add_size < del_size) {
- char *tmp= text->curl->line;
- memmove(tmp+text->curc+add_size, tmp+text->curc+del_size, text->curl->len-text->curc-del_size+1);
- }
-
- memcpy(text->curl->line + text->curc, ch, add_size);
- text->curc+= add_size;
-
- txt_pop_sel(text);
- txt_make_dirty(text);
- txt_clean_text(text);
- /* Should probably create a new op for this */
- if (!undoing) {
- txt_undo_add_charop(text, UNDO_DEL_1, del);
- txt_undo_add_charop(text, UNDO_INSERT_1, add);
- }
- return 1;
- }
- void txt_indent(Text *text)
- {
- int len, num;
- char *tmp;
- const char *add = "\t";
- int indentlen = 1;
-
- /* hardcoded: TXT_TABSIZE = 4 spaces: */
- int spaceslen = TXT_TABSIZE;
- if (ELEM3(NULL, text, text->curl, text->sell)) {
- return;
- }
- if (!text) return;
- if (!text->curl) return;
- if (!text->sell) return;
- /* insert spaces rather than tabs */
- if (text->flags & TXT_TABSTOSPACES) {
- add = tab_to_spaces;
- indentlen = spaceslen;
- }
- num = 0;
- while (TRUE)
- {
- tmp= MEM_mallocN(text->curl->len+indentlen+1, "textline_string");
-
- text->curc = 0;
- if (text->curc) memcpy(tmp, text->curl->line, text->curc); /* XXX never true, check prev line */
- memcpy(tmp+text->curc, add, indentlen);
-
- len= text->curl->len - text->curc;
- if (len>0) memcpy(tmp+text->curc+indentlen, text->curl->line+text->curc, len);
- tmp[text->curl->len+indentlen]= 0;
- make_new_line(text->curl, tmp);
-
- text->curc+= indentlen;
-
- txt_make_dirty(text);
- txt_clean_text(text);
-
- if (text->curl == text->sell)
- {
- text->selc = text->sell->len;
- break;
- }
- else {
- text->curl = text->curl->next;
- num++;
- }
- }
- text->curc = 0;
- while ( num > 0 )
- {
- text->curl = text->curl->prev;
- num--;
- }
-
- if (!undoing)
- {
- 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);
- }
- }
- void txt_unindent(Text *text)
- {
- int num = 0;
- const char *remove = "\t";
- int indent = 1;
-
- /* hardcoded: TXT_TABSIZE = 4 spaces: */
- int spaceslen = TXT_TABSIZE;
- if (!text) return;
- if (!text->curl) return;
- if (!text->sell) return;
- /* insert spaces rather than tabs */
- if (text->flags & TXT_TABSTOSPACES) {
- remove = tab_to_spaces;
- indent = spaceslen;
- }
- while (TRUE)
- {
- int i = 0;
-
- if (BLI_strncasecmp(text->curl->line, remove, indent) == 0)
- {
- while (i< text->curl->len) {
- text->curl->line[i]= text->curl->line[i+indent];
- i++;
- }
- text->curl->len-= indent;
- }
-
- txt_make_dirty(text);
- txt_clean_text(text);
-
- if (text->curl == text->sell)
- {
- text->selc = text->sell->len;
- break;
- }
- else {
- text->curl = text->curl->next;
- num++;
- }
-
- }
- text->curc = 0;
- while ( num > 0 )
- {
- text->curl = text->curl->prev;
- num--;
- }
-
- if (!undoing)
- {
- 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);
- }
- }
- void txt_comment(Text *text)
- {
- int len, num;
- char *tmp;
- char add = '#';
-
- if (!text) return;
- if (!text->curl) return;
- if (!text->sell) return;// Need to change this need to check if only one line is selected to more then one
- num = 0;
- while (TRUE)
- {
- tmp= MEM_mallocN(text->curl->len+2, "textline_string");
-
- text->curc = 0;
- if (text->curc) memcpy(tmp, text->curl->line, text->curc);
- tmp[text->curc]= add;
-
- len= text->curl->len - text->curc;
- if (len>0) memcpy(tmp+text->curc+1, text->curl->line+text->curc, len);
- tmp[text->curl->len+1]=0;
- make_new_line(text->curl, tmp);
-
- text->curc++;
-
- txt_make_dirty(text);
- txt_clean_text(text);
-
- if (text->curl == text->sell)
- {
- text->selc = text->sell->len;
- break;
- }
- else {
- text->curl = text->curl->next;
- num++;
- }
- }
- text->curc = 0;
- while ( num > 0 )
- {
- text->curl = text->curl->prev;
- num--;
- }
-
- if (!undoing)
- {
- 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);
- }
- }
- void txt_uncomment(Text *text)
- {
- int num = 0;
- char remove = '#';
-
- if (!text) return;
- if (!text->curl) return;
- if (!text->sell) return;
- while (TRUE)
- {
- int i = 0;
-
- if (text->curl->line[i] == remove)
- {
- while (i< text->curl->len) {
- text->curl->line[i]= text->curl->line[i+1];
- i++;
- }
- text->curl->len--;
- }
-
-
- txt_make_dirty(text);
- txt_clean_text(text);
-
- if (text->curl == text->sell)
- {
- text->selc = text->sell->len;
- break;
- }
- else {
- text->curl = text->curl->next;
- num++;
- }
-
- }
- text->curc = 0;
- while ( num > 0 )
- {
- text->curl = text->curl->prev;
- num--;
- }
-
- if (!undoing)
- {
- 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);
- }
- }
- int setcurr_tab_spaces (Text *text, int space)
- {
- int i = 0;
- int test = 0;
- const char *word = ":";
- const char *comm = "#";
- const char indent= (text->flags & TXT_TABSTOSPACES) ? ' ' : '\t';
- static const char *back_words[]= {"return", "break", "continue", "pass", "yield", NULL};
- if (!text) return 0;
- if (!text->curl) return 0;
- while (text->curl->line[i] == indent)
- {
- //we only count those tabs/spaces that are before any text or before the curs;
- if (i == text->curc)
- {
- return i;
- }
- else {
- i++;
- }
- }
- if (strstr(text->curl->line, word))
- {
- /* if we find a ':' on this line, then add a tab but not if it is:
- * 1) in a comment
- * 2) within an identifier
- * 3) after the cursor (text->curc), i.e. when creating space before a function def [#25414]
- */
- int a, is_indent = 0;
- for (a=0; (a < text->curc) && (text->curl->line[a] != '\0'); a++)
- {
- char ch= text->curl->line[a];
- if (ch=='#') {
- break;
- }
- else if (ch==':') {
- is_indent = 1;
- }
- else if (ch!=' ' && ch!='\t') {
- is_indent = 0;
- }
- }
- if (is_indent) {
- i += space;
- }
- }
- for (test=0; back_words[test]; test++)
- {
- /* if there are these key words then remove a tab because we are done with the block */
- if (strstr(text->curl->line, back_words[test]) && i > 0)
- {
- if (strcspn(text->curl->line, back_words[test]) < strcspn(text->curl->line, comm))
- {
- i -= space;
- }
- }
- }
- return i;
- }
- /*********************************/
- /* Text marker utility functions */
- /*********************************/
- /* Creates and adds a marker to the list maintaining sorted order */
- void txt_add_marker(Text *text, TextLine *line, int start, int end, const unsigned char color[4], int group, int flags)
- {
- TextMarker *tmp, *marker;
- marker= MEM_mallocN(sizeof(TextMarker), "text_marker");
-
- marker->lineno= txt_get_span(text->lines.first, line);
- marker->start= MIN2(start, end);
- marker->end= MAX2(start, end);
- marker->group= group;
- marker->flags= flags;
- marker->color[0]= color[0];
- marker->color[1]= color[1];
- marker->color[2]= color[2];
- marker->color[3]= color[3];
- for (tmp=text->markers.last; tmp; tmp=tmp->prev)
- if (tmp->lineno < marker->lineno || (tmp->lineno==marker->lineno && tmp->start < marker->start))
- break;
- if (tmp) BLI_insertlinkafter(&text->markers, tmp, marker);
- else BLI_addhead(&text->markers, marker);
- }
- /* Returns the first matching marker on the specified line between two points.
- * If the group or flags fields are non-zero the returned flag must be in the
- * specified group and have at least the specified flags set. */
- TextMarker *txt_find_marker_region(Text *text, TextLine *line, int start, int end, int group, int flags)
- {
- TextMarker *marker, *next;
- int lineno= txt_get_span(text->lines.first, line);
-
- for (marker=text->markers.first; marker; marker=next) {
- next= marker->next;
- if (group && marker->group != group) continue;
- else if ((marker->flags & flags) != flags) continue;
- else if (marker->lineno < lineno) continue;
- else if (marker->lineno > lineno) break;
- if ((marker->start==marker->end && start<=marker->start && marker->start<=end) ||
- (marker->start<end && marker->end>start))
- return marker;
- }
- return NULL;
- }
- /* Clears all markers on the specified line between two points. If the group or
- * flags fields are non-zero the returned flag must be in the specified group
- * and have at least the specified flags set. */
- short txt_clear_marker_region(Text *text, TextLine *line, int start, int end, int group, int flags)
- {
- TextMarker *marker, *next;
- int lineno= txt_get_span(text->lines.first, line);
- short cleared= 0;
-
- for (marker=text->markers.first; marker; marker=next) {
- next= marker->next;
- if (group && marker->group != group) continue;
- else if ((marker->flags & flags) != flags) continue;
- else if (marker->lineno < lineno) continue;
- else if (marker->lineno > lineno) break;
- if ((marker->start==marker->end && start<=marker->start && marker->start<=end) ||
- (marker->start<end && marker->end>start)) {
- BLI_freelinkN(&text->markers, marker);
- cleared= 1;
- }
- }
- return cleared;
- }
- /* Clears all markers in the specified group (if given) with at least the
- * specified flags set. Useful for clearing temporary markers (group=0,
- * flags=TMARK_TEMP) */
- short txt_clear_markers(Text *text, int group, int flags)
- {
- TextMarker *marker, *next;
- short cleared= 0;
-
- for (marker=text->markers.first; marker; marker=next) {
- next= marker->next;
- if ((!group || marker->group==group) &&
- (marker->flags & flags) == flags) {
- BLI_freelinkN(&text->markers, marker);
- cleared= 1;
- }
- }
- return cleared;
- }
- /* Finds the marker at the specified line and cursor position with at least the
- * specified flags set in the given group (if non-zero). */
- TextMarker *txt_find_marker(Text *text, TextLine *line, int curs, int group, int flags)
- {
- TextMarker *marker;
- int lineno= txt_get_span(text->lines.first, line);
-
- for (marker=text->markers.first; marker; marker=marker->next) {
- if (group && marker->group != group) continue;
- else if ((marker->flags & flags) != flags) continue;
- else if (marker->lineno < lineno) continue;
- else if (marker->lineno > lineno) break;
- if (marker->start <= curs && curs <= marker->end)
- return marker;
- }
- return NULL;
- }
- /* Finds the previous marker in the same group. If no other is found, the same
- * marker will be returned */
- TextMarker *txt_prev_marker(Text *text, TextMarker *marker)
- {
- TextMarker *tmp= marker;
- while (tmp) {
- if (tmp->prev) tmp= tmp->prev;
- else tmp= text->markers.last;
- if (tmp->group == marker->group)
- return tmp;
- }
- return NULL; /* Only if marker==NULL */
- }
- /* Finds the next marker in the same group. If no other is found, the same
- * marker will be returned */
- TextMarker *txt_next_marker(Text *text, TextMarker *marker)
- {
- TextMarker *tmp= marker;
- while (tmp) {
- if (tmp->next) tmp= tmp->next;
- else tmp= text->markers.first;
- if (tmp->group == marker->group)
- return tmp;
- }
- return NULL; /* Only if marker==NULL */
- }
- /*******************************/
- /* Character utility functions */
- /*******************************/
- int text_check_bracket(const char ch)
- {
- int a;
- char opens[] = "([{";
- char close[] = ")]}";
- for (a=0; a<(sizeof(opens)-1); a++) {
- if (ch==opens[a])
- return a+1;
- else if (ch==close[a])
- return -(a+1);
- }
- return 0;
- }
- /* TODO, have a function for operators - http://docs.python.org/py3k/reference/lexical_analysis.html#operators */
- int text_check_delim(const char ch)
- {
- int a;
- char delims[] = "():\"\' ~!%^&*-+=[]{};/<>|.#\t,@";
- for (a=0; a<(sizeof(delims)-1); a++) {
- if (ch==delims[a])
- return 1;
- }
- return 0;
- }
- int text_check_digit(const char ch)
- {
- if (ch < '0') return 0;
- if (ch <= '9') return 1;
- return 0;
- }
- int text_check_identifier(const char ch)
- {
- if (ch < '0') return 0;
- if (ch <= '9') return 1;
- if (ch < 'A') return 0;
- if (ch <= 'Z' || ch == '_') return 1;
- if (ch < 'a') return 0;
- if (ch <= 'z') return 1;
- return 0;
- }
- int text_check_whitespace(const char ch)
- {
- if (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n')
- return 1;
- return 0;
- }