remove use of deprecated struct members
[blender.git] / source / blender / blenkernel / intern / text.c
index 98ff0b2da1a47ef52ff3627865ac8e7a7a9de613..60cc029bf6e0d336fa4013b511d3186fc433476f 100644 (file)
@@ -1,8 +1,4 @@
-/* text.c
- *
- *
- * $Id$
- *
+/*
  * ***** BEGIN GPL LICENSE BLOCK *****
  *
  * This program is free software; you can redistribute it and/or
  * ***** END GPL LICENSE BLOCK *****
  */
 
+/** \file blender/blenkernel/intern/text.c
+ *  \ingroup bke
+ */
+
+
 #include <string.h> /* strstr */
 #include <sys/types.h>
 #include <sys/stat.h>
@@ -36,6 +37,7 @@
 #include "MEM_guardedalloc.h"
 
 #include "BLI_blenlib.h"
+#include "BLI_utildefines.h"
 
 #include "DNA_constraint_types.h"
 #include "DNA_controller_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"
-#include "BKE_utildefines.h"
 
-#ifndef DISABLE_PYTHON
-#include "BPY_extern.h"
-#endif
 
-#ifdef HAVE_CONFIG_H
-#include <config.h>
+#ifdef WITH_PYTHON
+#include "BPY_extern.h"
 #endif
 
 /***************/ /*
@@ -95,7 +95,7 @@ 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 colour.
+same template with the same color.
 
 Undo
 --
@@ -169,17 +169,18 @@ void free_text(Text *text)
 
        if(text->name) MEM_freeN(text->name);
        MEM_freeN(text->undo_buf);
-#ifndef DISABLE_PYTHON
-       if (text->compiled) BPY_free_compiled_text(text);
+#ifdef WITH_PYTHON
+       if (text->compiled) BPY_text_free_code(text);
 #endif
 }
 
-Text *add_empty_text(char *name) 
+Text *add_empty_text(const char *name) 
 {
+       Main *bmain= G.main;
        Text *ta;
        TextLine *tmp;
        
-       ta= alloc_libblock(&G.main->text, ID_TXT, name);
+       ta= alloc_libblock(&bmain->text, ID_TXT, name);
        ta->id.us= 1;
        
        ta->name= NULL;
@@ -233,18 +234,16 @@ static void cleanup_textline(TextLine * tl)
 int reopen_text(Text *text)
 {
        FILE *fp;
-       int i, llen, len, res;
+       int i, llen, len;
        unsigned char *buffer;
        TextLine *tmp;
-       char sfile[FILE_MAXFILE];
-       char str[FILE_MAXDIR+FILE_MAXFILE];
+       char str[FILE_MAX];
        struct stat st;
 
        if (!text || !text->name) return 0;
        
-       BLI_strncpy(str, text->name, FILE_MAXDIR+FILE_MAXFILE);
-       BLI_path_abs(str, G.sce);
-       BLI_split_dirfile(str, NULL, sfile);
+       BLI_strncpy(str, text->name, FILE_MAX);
+       BLI_path_abs(str, G.main->name);
        
        fp= fopen(str, "r");
        if(fp==NULL) return 0;
@@ -278,11 +277,10 @@ int reopen_text(Text *text)
 
        fclose(fp);
 
-       res= stat(str, &st);
+       stat(str, &st);
        text->mtime= st.st_mtime;
        
        text->nlines=0;
-       i=0;
        llen=0;
        for(i=0; i<len; i++) {
                if (buffer[i]=='\n') {
@@ -328,26 +326,25 @@ int reopen_text(Text *text)
        return 1;
 }
 
-Text *add_text(char *file, const char *relpath) 
+Text *add_text(const char *file, const char *relpath) 
 {
+       Main *bmain= G.main;
        FILE *fp;
-       int i, llen, len, res;
+       int i, llen, len;
        unsigned char *buffer;
        TextLine *tmp;
        Text *ta;
-       char sfile[FILE_MAXFILE];
-       char str[FILE_MAXDIR+FILE_MAXFILE];
+       char str[FILE_MAX];
        struct stat st;
 
-       BLI_strncpy(str, file, FILE_MAXDIR+FILE_MAXFILE);
+       BLI_strncpy(str, file, FILE_MAX);
        if (relpath) /* can be NULL (bg mode) */
                BLI_path_abs(str, relpath);
-       BLI_split_dirfile(str, NULL, sfile);
        
        fp= fopen(str, "r");
        if(fp==NULL) return NULL;
        
-       ta= alloc_libblock(&G.main->text, ID_TXT, sfile);
+       ta= alloc_libblock(&bmain->text, ID_TXT, BLI_path_basename(str));
        ta->id.us= 1;
 
        ta->lines.first= ta->lines.last= NULL;
@@ -373,11 +370,10 @@ Text *add_text(char *file, const char *relpath)
 
        fclose(fp);
 
-       res= stat(str, &st);
+       stat(str, &st);
        ta->mtime= st.st_mtime;
        
        ta->nlines=0;
-       i=0;
        llen=0;
        for(i=0; i<len; i++) {
                if (buffer[i]=='\n') {
@@ -400,7 +396,13 @@ Text *add_text(char *file, const char *relpath)
                llen++;
        }
 
-       if (llen!=0 || ta->nlines==0) {
+       /* 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;
@@ -429,7 +431,7 @@ Text *copy_text(Text *ta)
        Text *tan;
        TextLine *line, *tmp;
        
-       tan= copy_libblock(ta);
+       tan= copy_libblock(&ta->id);
        
        /* file name can be NULL */
        if(ta->name) {
@@ -477,17 +479,11 @@ void unlink_text(Main *bmain, Text *text)
        bScreen *scr;
        ScrArea *area;
        SpaceLink *sl;
-       Scene *scene;
        Object *ob;
        bController *cont;
        bConstraint *con;
        short update;
 
-       /* dome */
-       for(scene=bmain->scene.first; scene; scene=scene->id.next)
-               if(scene->r.dometext == text)
-                       scene->r.dometext = NULL;
-       
        for(ob=bmain->object.first; ob; ob=ob->id.next) {
                /* game controllers */
                for(cont=ob->controllers.first; cont; cont=cont->next) {
@@ -525,7 +521,7 @@ void unlink_text(Main *bmain, Text *text)
                }
                
                if(update)
-                       DAG_id_flush_update(&ob->id, OB_RECALC_DATA);
+                       DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
        }
 
        /* pynodes */
@@ -563,7 +559,7 @@ void clear_text(Text *text) /* called directly from rna */
        txt_make_dirty(text);
 }
 
-void write_text(Text *text, char *str) /* called directly from rna */
+void write_text(Text *text, const char *str) /* called directly from rna */
 {
        int oldstate;
 
@@ -589,7 +585,7 @@ static void make_new_line (TextLine *line, char *newline)
        line->format= NULL;
 }
 
-static TextLine *txt_new_line(char *str)
+static TextLine *txt_new_line(const char *str)
 {
        TextLine *tmp;
 
@@ -687,8 +683,8 @@ int txt_get_span (TextLine *from, TextLine *to)
 static void txt_make_dirty (Text *text)
 {
        text->flags |= TXT_ISDIRTY;
-#ifndef DISABLE_PYTHON
-       if (text->compiled) BPY_free_compiled_text(text);
+#ifdef WITH_PYTHON
+       if (text->compiled) BPY_text_free_code(text);
 #endif
 }
 
@@ -794,6 +790,7 @@ void txt_move_left(Text *text, short sel)
 {
        TextLine **linep;
        int *charp, oundoing= undoing;
+       int tabsize = 1, i=0;
        
        if (!text) return;
        if(sel) txt_curs_sel(text, &linep, &charp);
@@ -801,14 +798,34 @@ void txt_move_left(Text *text, short sel)
        if (!*linep) return;
 
        undoing= 1;
+
+       // do nice left only if there are only spaces
+       // TXT_TABSIZE hardcoded in DNA_text_types.h
+       if (text->flags & TXT_TABSTOSPACES) {
+               tabsize = TXT_TABSIZE;
+
+               if (*charp < tabsize)
+                       tabsize = *charp;
+               else {
+                       for (i=0;i<(*charp);i++)
+                               if ((*linep)->line[i] != ' ') {
+                                       tabsize = 1;
+                                       break;
+                               }
+                       // if in the middle of the space-tab
+                       if ((*charp) % tabsize != 0)
+                                       tabsize = ((*charp) % tabsize);
+               }
+       }
+
        if (*charp== 0) {
                if ((*linep)->prev) {
                        txt_move_up(text, sel);
                        *charp= (*linep)->len;
                }
-       } else {
-               (*charp)--;
        }
+       else (*charp)-= tabsize;
+
        undoing= oundoing;
        if(!undoing) txt_undo_add_op(text, sel?UNDO_SLEFT:UNDO_CLEFT);
        
@@ -819,6 +836,7 @@ void txt_move_right(Text *text, short sel)
 {
        TextLine **linep;
        int *charp, oundoing= undoing;
+       int tabsize=1, i=0;
        
        if (!text) return;
        if(sel) txt_curs_sel(text, &linep, &charp);
@@ -826,13 +844,32 @@ void txt_move_right(Text *text, short sel)
        if (!*linep) return;
 
        undoing= 1;
+
+       // do nice right only if there are only spaces
+       // spaces hardcoded in DNA_text_types.h
+       if (text->flags & TXT_TABSTOSPACES) {
+               tabsize = TXT_TABSIZE;
+
+               if ((*charp) + tabsize > (*linep)->len)
+                       tabsize = 1;
+               else {
+                       for (i=0;i<(*charp) + tabsize - ((*charp) % tabsize);i++)
+                               if ((*linep)->line[i] != ' ') {
+                                       tabsize = 1;
+                                       break;
+                               }
+                       // if in the middle of the space-tab
+                       tabsize -= (*charp) % tabsize;
+               }
+       }
+
        if (*charp== (*linep)->len) {
                if ((*linep)->next) {
                        txt_move_down(text, sel);
                        *charp= 0;
                }
        } else {
-               (*charp)++;
+               (*charp)+=tabsize;
        }
        undoing= oundoing;
        if(!undoing) txt_undo_add_op(text, sel?UNDO_SRIGHT:UNDO_CRIGHT);
@@ -995,8 +1032,8 @@ void txt_move_to (Text *text, unsigned int line, unsigned int ch, short sel)
                if ((*linep)->next) *linep= (*linep)->next;
                else break;
        }
-       if (ch>(*linep)->len)
-               ch= (*linep)->len;
+       if (ch>(unsigned int)((*linep)->len))
+               ch= (unsigned int)((*linep)->len);
        *charp= ch;
        
        if(!sel) txt_pop_sel(text);
@@ -1232,23 +1269,19 @@ char *txt_to_buf (Text *text)
        return buf;
 }
 
-int txt_find_string(Text *text, char *findstr, int wrap)
+int txt_find_string(Text *text, const char *findstr, int wrap, int match_case)
 {
        TextLine *tl, *startl;
        char *s= NULL;
-       int oldcl, oldsl, oldcc, oldsc;
 
        if (!text || !text->curl || !text->sell) return 0;
        
        txt_order_cursors(text);
 
-       oldcl= txt_get_span(text->lines.first, text->curl);
-       oldsl= txt_get_span(text->lines.first, text->sell);
        tl= startl= text->sell;
-       oldcc= text->curc;
-       oldsc= text->selc;
        
-       s= strstr(&tl->line[text->selc], findstr);
+       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) {
@@ -1258,7 +1291,8 @@ int txt_find_string(Text *text, char *findstr, int wrap)
                                break;
                }
 
-               s= strstr(tl->line, findstr);
+               if(match_case) s= strstr(tl->line, findstr);
+               else s= BLI_strcasestr(tl->line, findstr);
                if (tl==startl)
                        break;
        }
@@ -1350,9 +1384,19 @@ char *txt_sel_to_buf (Text *text)
        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 i=0, l=0, j, u, len;
+       int i=0, l=0, j, u, len, lineno= -1, count= 0;
        TextLine *add;
 
        if (!text) return;
@@ -1367,7 +1411,7 @@ void txt_insert_buf(Text *text, const char *in_buffer)
 
        /* Read the first line (or as close as possible */
        while (in_buffer[i] && in_buffer[i]!='\n') {
-               txt_add_char(text, in_buffer[i]);
+               txt_add_raw_char(text, in_buffer[i]);
                i++;
        }
        
@@ -1377,6 +1421,7 @@ void txt_insert_buf(Text *text, const char *in_buffer)
 
        /* Read as many full lines as we can */
        len= strlen(in_buffer);
+       lineno= txt_get_span(text->lines.first, text->curl);
 
        while (i<len) {
                l=0;
@@ -1389,15 +1434,28 @@ void txt_insert_buf(Text *text, const char *in_buffer)
                        add= txt_new_linen(in_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<(int)strlen(in_buffer); j++) {
-                               txt_add_char(text, in_buffer[j]);
+                               txt_add_raw_char(text, in_buffer[j]);
                        }
                        break;
                }
        }
-       
+
+       if(count) {
+               txt_shift_markers(text, lineno, count);
+               count= 0;
+       }
+
        undoing= u;
+
+       (void)count;
 }
 
 /******************/
@@ -1435,7 +1493,7 @@ void txt_print_undo(Text *text)
 {
        int i= 0;
        int op;
-       char *ops;
+       const char *ops;
        int linep, charp;
        
        dump_buffer(text);
@@ -1872,13 +1930,13 @@ void txt_do_undo(Text *text)
 
                        
                        if (op==UNDO_INDENT) {
-                               unindent(text);
+                               txt_unindent(text);
                        } else if (op== UNDO_UNINDENT) {
-                               indent(text);
+                               txt_indent(text);
                        } else if (op == UNDO_COMMENT) {
-                               uncomment(text);
+                               txt_uncomment(text);
                        } else if (op == UNDO_UNCOMMENT) {
-                               comment(text);
+                               txt_comment(text);
                        }
 
                        text->undo_pos--;
@@ -2048,6 +2106,7 @@ void txt_do_redo(Text *text)
                        linep= linep+(text->undo_buf[text->undo_pos]<<8); text->undo_pos++;
                        linep= linep+(text->undo_buf[text->undo_pos]<<16); text->undo_pos++;
                        linep= linep+(text->undo_buf[text->undo_pos]<<24); text->undo_pos++;
+                       (void)linep;
 
                        break;
                case UNDO_INDENT:
@@ -2087,13 +2146,13 @@ void txt_do_redo(Text *text)
                        }
 
                        if (op==UNDO_INDENT) {
-                               indent(text);
+                               txt_indent(text);
                        } else if (op== UNDO_UNINDENT) {
-                               unindent(text);
+                               txt_unindent(text);
                        } else if (op == UNDO_COMMENT) {
-                               comment(text);
+                               txt_comment(text);
                        } else if (op == UNDO_UNCOMMENT) {
-                               uncomment(text);
+                               txt_uncomment(text);
                        }
                        break;
                default:
@@ -2223,7 +2282,6 @@ static void txt_combine_lines (Text *text, TextLine *linea, TextLine *lineb)
                } while (mrk && mrk->lineno==lineno);
        }
        if (lineno==-1) lineno= txt_get_span(text->lines.first, lineb);
-       if (!mrk) mrk= text->markers.first;
        
        tmp= MEM_mallocN(linea->len+lineb->len+1, "textline_string");
        
@@ -2378,7 +2436,7 @@ static void txt_convert_tab_to_spaces (Text *text)
        txt_insert_buf(text, sb);
 }
 
-int txt_add_char (Text *text, char add) 
+static int txt_add_char_intern (Text *text, char add, int replace_tabs)
 {
        int len, lineno;
        char *tmp;
@@ -2392,8 +2450,8 @@ int txt_add_char (Text *text, char add)
                return 1;
        }
        
-       /* insert spaces rather then tabs */
-       if (add == '\t' && text->flags & TXT_TABSTOSPACES) {
+       /* insert spaces rather than tabs */
+       if (add == '\t' && replace_tabs) {
                txt_convert_tab_to_spaces(text);
                return 1;
        }
@@ -2431,6 +2489,16 @@ int txt_add_char (Text *text, char add)
        return 1;
 }
 
+int txt_add_char (Text *text, char add)
+{
+       return txt_add_char_intern(text, add, text->flags & TXT_TABSTOSPACES);
+}
+
+int txt_add_raw_char (Text *text, char add)
+{
+       return txt_add_char_intern(text, add, 0);
+}
+
 void txt_delete_selected(Text *text)
 {
        txt_delete_sel(text);
@@ -2469,18 +2537,18 @@ int txt_replace_char (Text *text, char add)
        return 1;
 }
 
-void indent(Text *text)
+void txt_indent(Text *text)
 {
        int len, num;
        char *tmp;
 
-       char *add = "\t";
+       const char *add = "\t";
        int indentlen = 1;
        
        /* hardcoded: TXT_TABSIZE = 4 spaces: */
        int spaceslen = TXT_TABSIZE;
 
-       /* insert spaces rather then tabs */
+       /* insert spaces rather than tabs */
        if (text->flags & TXT_TABSTOSPACES){
                add = tab_to_spaces;
                indentlen = spaceslen;
@@ -2532,16 +2600,16 @@ void indent(Text *text)
        }
 }
 
-void unindent(Text *text)
+void txt_unindent(Text *text)
 {
        int num = 0;
-       char *remove = "\t";
+       const char *remove = "\t";
        int indent = 1;
        
        /* hardcoded: TXT_TABSIZE = 4 spaces: */
        int spaceslen = TXT_TABSIZE;
 
-       /* insert spaces rather then tabs */
+       /* insert spaces rather than tabs */
        if (text->flags & TXT_TABSTOSPACES){
                remove = tab_to_spaces;
                indent = spaceslen;
@@ -2590,7 +2658,7 @@ void unindent(Text *text)
        }
 }
 
-void comment(Text *text)
+void txt_comment(Text *text)
 {
        int len, num;
        char *tmp;
@@ -2598,7 +2666,7 @@ void comment(Text *text)
        
        if (!text) return;
        if (!text->curl) return;
-       if (!text->sell) return;// Need to change this need to check if only one line is selected ot more then one
+       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)
@@ -2642,7 +2710,7 @@ void comment(Text *text)
        }
 }
 
-void uncomment(Text *text)
+void txt_uncomment(Text *text)
 {
        int num = 0;
        char remove = '#';
@@ -2691,19 +2759,20 @@ void uncomment(Text *text)
        }
 }
 
-int setcurr_tab (Text *text)
+int setcurr_tab_spaces (Text *text, int space)
 {
        int i = 0;
        int test = 0;
-       char *word = ":";
-       char *comm = "#";
-       char back_words[4][7] = {"return", "break", "pass", "yield"};
+       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] == '\t')
+
+       while (text->curl->line[i] == indent)
        {
-               //we only count thos tabs that are before any text or before the curs;
+               //we only count those tabs/spaces that are before any text or before the curs;
                if (i == text->curc)
                {
                        return i;
@@ -2713,31 +2782,36 @@ int setcurr_tab (Text *text)
        }
        if(strstr(text->curl->line, word))
        {
-               //if we find a : then add a tab but not if it is in a comment
-               int a, indent = 0;
-               for(a=0; text->curl->line[a] != '\0'; a++)
+               /* 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++)
                {
-                       if (text->curl->line[a]=='#') {
+                       char ch= text->curl->line[a];
+                       if (ch=='#') {
                                break;
-                       } else if (text->curl->line[a]==':') {
-                               indent = 1;
-                       } else if (text->curl->line[a]==']') {
-                               indent = 0;
+                       } else if (ch==':') {
+                               is_indent = 1;
+                       } else if (ch!=' ' && ch!='\t') {
+                               is_indent = 0;
                        }
                }
-               if (indent) {
-                       i++;
+               if (is_indent) {
+                       i += space;
                }
        }
 
-       for(test=0; test < 4; test++)
+       for(test=0; back_words[test]; test++)
        {
-               //if there are these 4 key words then remove a tab because we are done with the block
+               /* 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--;
+                               i -= space;
                        }
                }
        }
@@ -2749,7 +2823,8 @@ int setcurr_tab (Text *text)
 /*********************************/
 
 /* Creates and adds a marker to the list maintaining sorted order */
-void txt_add_marker(Text *text, TextLine *line, int start, int end, char color[4], int group, int flags) {
+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");
@@ -2798,7 +2873,8 @@ TextMarker *txt_find_marker_region(Text *text, TextLine *line, int start, int en
 /* 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) {
+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;
@@ -2823,7 +2899,8 @@ short txt_clear_marker_region(Text *text, TextLine *line, int start, int end, in
 /* 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) {
+short txt_clear_markers(Text *text, int group, int flags)
+{
        TextMarker *marker, *next;
        short cleared= 0;