patch [#29859] UTF-8 support for text editor.

This also fixes cursor movement in the beginning of line and adds do_versions block for converting text files with old extended ascii encoding into UTF-8.
This commit is contained in:
2012-01-16 16:23:25 +00:00
parent ae9582836e
commit c150d0084f
6 changed files with 878 additions and 563 deletions

View File

@@ -1420,7 +1420,7 @@ static int text_get_cursor_rel(SpaceText* st, ARegion *ar, TextLine *linein, int
end= max;
chop= loop= 1;
for(i=0, j=0; loop; j++) {
for(i=0, j=0; loop; j+=BLI_str_utf8_size(linein->line+j)) {
int chars;
/* Mimic replacement of tabs */
ch= linein->line[j];
@@ -1595,7 +1595,7 @@ static void txt_wrap_move_bol(SpaceText *st, ARegion *ar, short sel)
chop= loop= 1;
*charp= 0;
for(i=0, j=0; loop; j++) {
for(i=0, j=0; loop; j+=BLI_str_utf8_size((*linep)->line+j)) {
int chars;
/* Mimic replacement of tabs */
ch= (*linep)->line[j];
@@ -1610,7 +1610,7 @@ static void txt_wrap_move_bol(SpaceText *st, ARegion *ar, short sel)
*charp= endj;
if(j>=oldc) {
if(ch=='\0') *charp= start;
if(ch=='\0') *charp= txt_utf8_index_to_offset((*linep)->line, start);
loop= 0;
break;
}
@@ -1623,7 +1623,7 @@ static void txt_wrap_move_bol(SpaceText *st, ARegion *ar, short sel)
}
else if(ch==' ' || ch=='-' || ch=='\0') {
if(j>=oldc) {
*charp= start;
*charp= txt_utf8_index_to_offset((*linep)->line, start);
loop= 0;
break;
}
@@ -1663,7 +1663,7 @@ static void txt_wrap_move_eol(SpaceText *st, ARegion *ar, short sel)
chop= loop= 1;
*charp= 0;
for(i=0, j=0; loop; j++) {
for(i=0, j=0; loop; j+=BLI_str_utf8_size((*linep)->line+j)) {
int chars;
/* Mimic replacement of tabs */
ch= (*linep)->line[j];
@@ -1675,7 +1675,7 @@ static void txt_wrap_move_eol(SpaceText *st, ARegion *ar, short sel)
while(chars--) {
if(i-start>=max) {
if(chop) endj= j-1;
if(chop) endj= BLI_str_prev_char_utf8((*linep)->line+j)-(*linep)->line;
if(endj>=oldc) {
if(ch=='\0') *charp= (*linep)->len;
@@ -2364,148 +2364,183 @@ typedef struct SetSelection {
short old[2];
} SetSelection;
static int flatten_len(SpaceText *st, const char *str)
{
int i, total = 0;
for(i = 0; str[i]; i += BLI_str_utf8_size(str+i)) {
if(str[i]=='\t') {
total += st->tabnumber - total%st->tabnumber;
}
else total++;
}
return total;
}
static int flatten_index_to_offset(SpaceText *st, const char *str, int index)
{
int i, j;
for (i= 0, j= 0; i < index; j += BLI_str_utf8_size(str+j))
if(str[j]=='\t')
i += st->tabnumber - i%st->tabnumber;
else
i++;
return j;
}
static TextLine *get_first_visible_line(SpaceText *st, ARegion *ar, int *y)
{
TextLine *linep = st->text->lines.first;
int i;
for (i = st->top; i > 0 && linep; ) {
int lines = text_get_visible_lines(st, ar, linep->line);
if (i-lines < 0) {
*y += i;
break;
} else {
linep = linep->next;
i -= lines;
}
}
return linep;
}
static void text_cursor_set_to_pos_wrapped(SpaceText *st, ARegion *ar, int x, int y, int sel)
{
Text *text = st->text;
int max = wrap_width(st, ar); /* view */
int charp; /* mem */
int loop = 1, found = 0; /* flags */
char ch;
/* Point to first visible line */
TextLine *linep = get_first_visible_line(st, ar, &y);
while(loop && linep) {
int i = 0, start = 0, end = max; /* view */
int j = 0, curs = 0, endj = 0; /* mem */
int chop = 1; /* flags */
for (; loop; j += BLI_str_utf8_size(linep->line+j)) {
int chars;
/* Mimic replacement of tabs */
ch = linep->line[j];
if(ch == '\t') {
chars = st->tabnumber - i%st->tabnumber;
ch = ' ';
}
else chars = 1;
while (chars--) {
/* Gone too far, go back to last wrap point */
if (y < 0) {
charp = endj;
loop = 0;
break;
/* Exactly at the cursor */
}
else if (y == 0 && i-start == x) {
/* current position could be wrapped to next line */
/* this should be checked when end of current line would be reached */
charp = curs= j;
found = 1;
/* Prepare curs for next wrap */
}
else if(i - end == x) {
curs = j;
}
if (i - start >= max) {
if (found) {
/* exact cursor position was found, check if it's */
/* still on needed line (hasn't been wrapped) */
if (charp > endj && !chop && ch!='\0') charp = endj;
loop = 0;
break;
}
if(chop) endj = j;
start = end;
end += max;
if(j < linep->len)
y--;
chop = 1;
if (y == 0 && i-start >= x) {
charp = curs;
loop = 0;
break;
}
}
else if (ch == ' ' || ch == '-' || ch == '\0') {
if (found) {
loop = 0;
break;
}
if(y == 0 && i-start >= x) {
charp = curs;
loop = 0;
break;
}
end = i + 1;
endj = j;
chop = 0;
}
i++;
}
if(ch == '\0') break;
}
if(!loop || found) break;
if(!linep->next) {
charp = linep->len;
break;
}
/* On correct line but didn't meet cursor, must be at end */
if (y == 0) {
charp = linep->len;
break;
}
linep = linep->next;
y--;
}
if(sel) { text->sell = linep; text->selc = charp; }
else { text->curl = linep; text->curc = charp; }
}
static void text_cursor_set_to_pos(SpaceText *st, ARegion *ar, int x, int y, int sel)
{
FlattenString fs;
Text *text= st->text;
TextLine **linep;
int *charp;
int w;
text_update_character_width(st);
if(sel) { linep= &text->sell; charp= &text->selc; }
else { linep= &text->curl; charp= &text->curc; }
y= (ar->winy - 2 - y)/st->lheight;
if(st->showlinenrs)
x-= TXT_OFFSET+TEXTXLOC;
else
x-= TXT_OFFSET;
if(st->showlinenrs) x-= TXT_OFFSET+TEXTXLOC;
else x-= TXT_OFFSET;
if(x<0) x= 0;
x = (x/st->cwidth) + st->left;
if(st->wordwrap) {
int i, j, endj, curs, max, chop, start, end, loop, found;
char ch;
/* Point to first visible line */
*linep= text->lines.first;
i= st->top;
while(i>0 && *linep) {
int lines= text_get_visible_lines(st, ar, (*linep)->line);
if (i-lines<0) {
y+= i;
break;
} else {
*linep= (*linep)->next;
i-= lines;
}
}
max= wrap_width(st, ar);
loop= 1;
found= 0;
while(loop && *linep) {
start= 0;
end= max;
chop= 1;
curs= 0;
endj= 0;
for(i=0, j=0; loop; j++) {
int chars;
/* Mimic replacement of tabs */
ch= (*linep)->line[j];
if(ch=='\t') {
chars= st->tabnumber-i%st->tabnumber;
ch= ' ';
}
else
chars= 1;
while(chars--) {
/* Gone too far, go back to last wrap point */
if(y<0) {
*charp= endj;
loop= 0;
break;
/* Exactly at the cursor */
}
else if(y==0 && i-start==x) {
/* current position could be wrapped to next line */
/* this should be checked when end of current line would be reached */
*charp= curs= j;
found= 1;
/* Prepare curs for next wrap */
}
else if(i-end==x) {
curs= j;
}
if(i-start>=max) {
if(found) {
/* exact cursor position was found, check if it's */
/* still on needed line (hasn't been wrapped) */
if(*charp>endj && !chop && ch!='\0') (*charp)= endj;
loop= 0;
break;
}
if(chop) endj= j;
start= end;
end += max;
if(j<(*linep)->len)
y--;
chop= 1;
if(y==0 && i-start>=x) {
*charp= curs;
loop= 0;
break;
}
}
else if(ch==' ' || ch=='-' || ch=='\0') {
if(found) {
loop= 0;
break;
}
if(y==0 && i-start>=x) {
*charp= curs;
loop= 0;
break;
}
end = i+1;
endj = j;
chop= 0;
}
i++;
}
if(ch=='\0') break;
}
if(!loop || found) break;
if(!(*linep)->next) {
*charp= (*linep)->len;
break;
}
/* On correct line but didn't meet cursor, must be at end */
if(y==0) {
*charp= (*linep)->len;
break;
}
*linep= (*linep)->next;
y--;
}
text_cursor_set_to_pos_wrapped(st, ar, x, y, sel);
}
else {
TextLine **linep;
int *charp;
int w;
if(sel) { linep= &text->sell; charp= &text->selc; }
else { linep= &text->curl; charp= &text->curc; }
y-= txt_get_span(text->lines.first, *linep) - st->top;
if(y>0) {
@@ -2516,10 +2551,9 @@ static void text_cursor_set_to_pos(SpaceText *st, ARegion *ar, int x, int y, int
}
w= flatten_string(st, &fs, (*linep)->line);
if(x<w) *charp= fs.accum[x];
w= flatten_len(st, (*linep)->line);
if(x<w) *charp= flatten_index_to_offset(st, (*linep)->line, x);
else *charp= (*linep)->len;
flatten_string_free(&fs);
}
if(!sel) txt_pop_sel(text);
}
@@ -2762,19 +2796,23 @@ static int text_insert_exec(bContext *C, wmOperator *op)
SpaceText *st= CTX_wm_space_text(C);
Text *text= CTX_data_edit_text(C);
char *str;
int done = 0, i;
int done = 0;
size_t i = 0;
unsigned int code;
text_drawcache_tag_update(st, 0);
str= RNA_string_get_alloc(op->ptr, "text", NULL, 0);
if(st && st->overwrite) {
for(i=0; str[i]; i++) {
done |= txt_replace_char(text, str[i]);
while (str[i]) {
code = BLI_str_utf8_as_unicode_step(str, &i);
done |= txt_replace_char(text, code);
}
} else {
for(i=0; str[i]; i++) {
done |= txt_add_char(text, str[i]);
while (str[i]) {
code = BLI_str_utf8_as_unicode_step(str, &i);
done |= txt_add_char(text, code);
}
}
@@ -2802,9 +2840,17 @@ static int text_insert_invoke(bContext *C, wmOperator *op, wmEvent *event)
return OPERATOR_PASS_THROUGH;
}
else {
char str[2];
str[0]= event->ascii;
str[1]= '\0';
char str[BLI_UTF8_MAX+1];
size_t len;
if (event->utf8_buf[0]) {
len = BLI_str_utf8_size(event->utf8_buf);
memcpy(str, event->utf8_buf, len);
} else {
/* in theory, ghost can set value to extended ascii here */
len = BLI_str_utf8_from_unicode(event->ascii, str);
}
str[len]= '\0';
RNA_string_set(op->ptr, "text", str);
}
}