diff options
-rw-r--r-- | src/common.h | 2 | ||||
-rw-r--r-- | src/fe-text/gui-entry.c | 596 | ||||
-rw-r--r-- | src/fe-text/gui-entry.h | 11 | ||||
-rw-r--r-- | src/fe-text/irssi.c | 2 | ||||
-rw-r--r-- | src/perl/textui/TextUI.xs | 68 |
5 files changed, 607 insertions, 72 deletions
diff --git a/src/common.h b/src/common.h index ba5557e6..46d0c45a 100644 --- a/src/common.h +++ b/src/common.h @@ -6,7 +6,7 @@ #define IRSSI_GLOBAL_CONFIG "irssi.conf" /* config file name in /etc/ */ #define IRSSI_HOME_CONFIG "config" /* config file name in ~/.irssi/ */ -#define IRSSI_ABI_VERSION 13 +#define IRSSI_ABI_VERSION 14 #define DEFAULT_SERVER_ADD_PORT 6667 #define DEFAULT_SERVER_ADD_TLS_PORT 6697 diff --git a/src/fe-text/gui-entry.c b/src/fe-text/gui-entry.c index e91fcfb3..52a39969 100644 --- a/src/fe-text/gui-entry.c +++ b/src/fe-text/gui-entry.c @@ -65,6 +65,10 @@ static void entry_text_grow(GUI_ENTRY_REC *entry, int grow_size) entry->text_alloc = nearest_power(entry->text_alloc+grow_size); entry->text = g_realloc(entry->text, sizeof(unichar) * entry->text_alloc); + + if (entry->uses_extents) + entry->extents = g_realloc(entry->extents, + sizeof(char *) * entry->text_alloc); } GUI_ENTRY_REC *gui_entry_create(int xpos, int ypos, int width, int utf8) @@ -74,14 +78,30 @@ GUI_ENTRY_REC *gui_entry_create(int xpos, int ypos, int width, int utf8) rec = g_new0(GUI_ENTRY_REC, 1); rec->xpos = xpos; rec->ypos = ypos; - rec->width = width; - rec->text_alloc = 1024; + rec->width = width; + rec->text_alloc = 1024; rec->text = g_new(unichar, rec->text_alloc); - rec->text[0] = '\0'; - rec->utf8 = utf8; + rec->extents = NULL; + rec->text[0] = '\0'; + rec->utf8 = utf8; return rec; } +static void destroy_extents(GUI_ENTRY_REC *entry) +{ + if (entry->uses_extents) { + int i; + for (i = 0; i < entry->text_alloc; i++) { + if (entry->extents[i] != NULL) { + g_free(entry->extents[i]); + } + } + } + g_free(entry->extents); + entry->extents = NULL; + entry->uses_extents = FALSE; +} + void gui_entry_destroy(GUI_ENTRY_REC *entry) { GSList *tmp; @@ -100,9 +120,10 @@ void gui_entry_destroy(GUI_ENTRY_REC *entry) } g_slist_free(entry->kill_ring); - g_free(entry->text); + destroy_extents(entry); + g_free(entry->text); g_free(entry->prompt); - g_free(entry); + g_free(entry); } /* big5 functions */ @@ -164,15 +185,36 @@ void big5_to_unichars(const char *str, unichar *out) *out = '\0'; } +/* Return screen length of plain string */ +static int scrlen_str(const char *str, int utf8) +{ + int len = 0; + char *stripped; + g_return_val_if_fail(str != NULL, 0); + + stripped = strip_codes(str); + len = string_width(stripped, utf8 ? TREAT_STRING_AS_UTF8 : TREAT_STRING_AS_BYTES); + g_free(stripped); + return len; +} + /* ----------------------------- */ -static int pos2scrpos(GUI_ENTRY_REC *entry, int pos) +static int pos2scrpos(GUI_ENTRY_REC *entry, int pos, int cursor) { int i; int xpos = 0; + if (!cursor && pos <= 0) + return 0; + + if (entry->uses_extents && entry->extents[0] != NULL) { + xpos += scrlen_str(entry->extents[0], entry->utf8); + } + for (i = 0; i < pos; i++) { unichar c = entry->text[i]; + const char *extent = entry->uses_extents ? entry->extents[i+1] : NULL; if (term_type == TERM_TYPE_BIG5) xpos += big5_width(c); @@ -180,16 +222,26 @@ static int pos2scrpos(GUI_ENTRY_REC *entry, int pos) xpos += unichar_isprint(c) ? mk_wcwidth(c) : 1; else xpos++; + + if (extent != NULL) { + xpos += scrlen_str(extent, entry->utf8); + } + } return xpos; } static int scrpos2pos(GUI_ENTRY_REC *entry, int pos) { - int i, width, xpos; + int i, width, xpos = 0; - for (i = 0, xpos = 0; i < entry->text_len; i++) { + if (entry->uses_extents && entry->extents[0] != NULL) { + xpos += scrlen_str(entry->extents[0], entry->utf8); + } + + for (i = 0; i < entry->text_len && xpos < pos; i++) { unichar c = entry->text[i]; + const char *extent = entry->uses_extents ? entry->extents[i+1] : NULL; if (term_type == TERM_TYPE_BIG5) width = big5_width(c); @@ -198,15 +250,13 @@ static int scrpos2pos(GUI_ENTRY_REC *entry, int pos) else width = 1; - if (xpos + width > pos) - break; xpos += width; - } - if (xpos == pos) - return i; - else - return i-1; + if (extent != NULL) { + xpos += scrlen_str(extent, entry->utf8); + } + } + return i; } /* Fixes the cursor position in screen */ @@ -215,19 +265,19 @@ static void gui_entry_fix_cursor(GUI_ENTRY_REC *entry) int old_scrstart; /* assume prompt len == prompt scrlen */ - int start = pos2scrpos(entry, entry->scrstart); - int now = pos2scrpos(entry, entry->pos); + int start = pos2scrpos(entry, entry->scrstart, FALSE); + int now = pos2scrpos(entry, entry->pos, TRUE); old_scrstart = entry->scrstart; - if (now-start < entry->width - 2 - entry->promptlen && now-start > 0) + if (now-start < entry->width - 2 - entry->promptlen && now-start > 0) { entry->scrpos = now-start; - else if (now < entry->width - 1 - entry->promptlen) { + } else if (now < entry->width - 1 - entry->promptlen) { entry->scrstart = 0; entry->scrpos = now; } else { entry->scrstart = scrpos2pos(entry, now-(entry->width - entry->promptlen)*2/3); - start = pos2scrpos(entry, entry->scrstart); + start = pos2scrpos(entry, entry->scrstart, FALSE); entry->scrpos = now - start; } @@ -235,59 +285,140 @@ static void gui_entry_fix_cursor(GUI_ENTRY_REC *entry) entry->redraw_needed_from = 0; } +static char *text_effects_only(const char *p) +{ + GString *str; + + str = g_string_sized_new(strlen(p)); + for (; *p != '\0'; p++) { + if (*p == 4 && p[1] != '\0') { + if (p[1] >= FORMAT_STYLE_SPECIAL) { + g_string_append_len(str, p, 2); + p++; + continue; + } + + /* irssi color */ + if (p[2] != '\0') { +#ifdef TERM_TRUECOLOR + if (p[1] == FORMAT_COLOR_24) { + if (p[3] == '\0') p += 2; + else if (p[4] == '\0') p += 3; + else if (p[5] == '\0') p += 4; + else { + g_string_append_len(str, p, 6); + p += 5; + } + } else { +#endif /* TERM_TRUECOLOR */ + g_string_append_len(str, p, 3); + p += 2; +#ifdef TERM_TRUECOLOR + } +#endif /* TERM_TRUECOLOR */ + continue; + } + } + } + + return g_string_free(str, FALSE); +} + static void gui_entry_draw_from(GUI_ENTRY_REC *entry, int pos) { - int i; - int xpos, end_xpos; + int i, start; + int start_xpos, xpos, new_xpos, end_xpos; + char *tmp; + GString *str; + + start = entry->scrstart + pos; - xpos = entry->xpos + entry->promptlen + - pos2scrpos(entry, pos + entry->scrstart) - - pos2scrpos(entry, entry->scrstart); + start_xpos = xpos = entry->xpos + entry->promptlen + + pos2scrpos(entry, start, FALSE) - + pos2scrpos(entry, entry->scrstart, FALSE); end_xpos = entry->xpos + entry->width; if (xpos > end_xpos) return; + str = g_string_sized_new(entry->text_alloc); + term_set_color(root_window, ATTR_RESET); - term_move(root_window, xpos, entry->ypos); + /* term_move(root_window, xpos, entry->ypos); */ + + if (entry->uses_extents && entry->extents[0] != NULL) { + g_string_append(str, entry->extents[0]); + } + for (i = 0; i < start && i < entry->text_len; i++) { + const char *extent = entry->uses_extents ? entry->extents[i+1] : NULL; + if (extent != NULL) { + g_string_append(str, extent); + } + } + if (i == 0) { + xpos += scrlen_str(str->str, entry->utf8); + } else { + tmp = text_effects_only(str->str); + g_string_assign(str, tmp); + g_free(tmp); + } - for (i = entry->scrstart + pos; i < entry->text_len; i++) { + for (; i < entry->text_len; i++) { unichar c = entry->text[i]; + const char *extent = entry->uses_extents ? entry->extents[i+1] : NULL; + new_xpos = xpos; if (entry->hidden) - xpos++; + new_xpos++; else if (term_type == TERM_TYPE_BIG5) - xpos += big5_width(c); + new_xpos += big5_width(c); else if (entry->utf8) - xpos += unichar_isprint(c) ? mk_wcwidth(c) : 1; + new_xpos += unichar_isprint(c) ? mk_wcwidth(c) : 1; else - xpos++; + new_xpos++; - if (xpos > end_xpos) + if (new_xpos > end_xpos) break; if (entry->hidden) - term_addch(root_window, ' '); + g_string_append_c(str, ' '); else if (unichar_isprint(c)) - term_add_unichar(root_window, c); + g_string_append_unichar(str, c); else { - term_set_color(root_window, ATTR_RESET|ATTR_REVERSE); - term_addch(root_window, (c & 127)+'A'-1); - term_set_color(root_window, ATTR_RESET); + g_string_append_c(str, 4); + g_string_append_c(str, FORMAT_STYLE_REVERSE); + g_string_append_c(str, (c & 127)+'A'-1); + g_string_append_c(str, 4); + g_string_append_c(str, FORMAT_STYLE_REVERSE); + } + xpos = new_xpos; + + if (extent != NULL) { + new_xpos += scrlen_str(extent, entry->utf8); + + if (new_xpos > end_xpos) + break; + + g_string_append(str, extent); + xpos = new_xpos; } } /* clear the rest of the input line */ if (xpos < end_xpos) { - if (end_xpos == term_width) - term_clrtoeol(root_window); - else { + if (end_xpos == term_width) { + g_string_append_c(str, 4); + g_string_append_c(str, FORMAT_STYLE_CLRTOEOL); + } else { while (xpos < end_xpos) { - term_addch(root_window, ' '); + g_string_append_c(str, ' '); xpos++; } } } + + gui_printtext_internal(start_xpos, entry->ypos, str->str); + g_string_free(str, TRUE); } static void gui_entry_draw(GUI_ENTRY_REC *entry) @@ -359,19 +490,6 @@ void gui_entry_set_active(GUI_ENTRY_REC *entry) } } -/* Return screen length of plain string */ -static int scrlen_str(const char *str) -{ - int len = 0; - char *stripped; - g_return_val_if_fail(str != NULL, 0); - - stripped = strip_codes(str); - len = string_width(stripped, -1); - g_free(stripped); - return len; -} - void gui_entry_set_prompt(GUI_ENTRY_REC *entry, const char *str) { int oldlen; @@ -382,7 +500,7 @@ void gui_entry_set_prompt(GUI_ENTRY_REC *entry, const char *str) if (str != NULL) { g_free_not_null(entry->prompt); entry->prompt = g_strdup(str); - entry->promptlen = scrlen_str(str); + entry->promptlen = scrlen_str(str, entry->utf8); } if (entry->prompt != NULL) @@ -416,6 +534,7 @@ void gui_entry_set_text(GUI_ENTRY_REC *entry, const char *str) entry->text_len = 0; entry->pos = 0; entry->text[0] = '\0'; + destroy_extents(entry); gui_entry_insert_text(entry, str); } @@ -488,6 +607,15 @@ void gui_entry_insert_text(GUI_ENTRY_REC *entry, const char *str) g_memmove(entry->text + entry->pos + len, entry->text + entry->pos, (entry->text_len-entry->pos + 1) * sizeof(unichar)); + /* make space for the color */ + if (entry->uses_extents) { + g_memmove(entry->extents + entry->pos + len + 1, entry->extents + entry->pos + 1, + (entry->text_len-entry->pos) * sizeof(char *)); + for (i = 0; i < len; i++) { + entry->extents[entry->pos + i + 1] = NULL; + } + } + if (!entry->utf8) { if (term_type == TERM_TYPE_BIG5) { chr = entry->text[entry->pos + len]; @@ -514,7 +642,7 @@ void gui_entry_insert_text(GUI_ENTRY_REC *entry, const char *str) void gui_entry_insert_char(GUI_ENTRY_REC *entry, unichar chr) { - g_return_if_fail(entry != NULL); + g_return_if_fail(entry != NULL); if (chr == 0 || chr == 13 || chr == 10) return; /* never insert NUL, CR or LF characters */ @@ -522,7 +650,7 @@ void gui_entry_insert_char(GUI_ENTRY_REC *entry, unichar chr) if (entry->utf8 && entry->pos == 0 && mk_wcwidth(chr) == 0) return; - gui_entry_redraw_from(entry, entry->pos); + gui_entry_redraw_from(entry, entry->pos); entry_text_grow(entry, 1); @@ -530,9 +658,15 @@ void gui_entry_insert_char(GUI_ENTRY_REC *entry, unichar chr) g_memmove(entry->text + entry->pos + 1, entry->text + entry->pos, (entry->text_len-entry->pos + 1) * sizeof(unichar)); + if (entry->uses_extents) { + g_memmove(entry->extents + entry->pos + 1 + 1, entry->extents + entry->pos + 1, + (entry->text_len-entry->pos) * sizeof(char *)); + entry->extents[entry->pos + 1] = NULL; + } + entry->text[entry->pos] = chr; entry->text_len++; - entry->pos++; + entry->pos++; gui_entry_fix_cursor(entry); gui_entry_draw(entry); @@ -631,7 +765,7 @@ static GUI_ENTRY_CUTBUFFER_REC *get_cutbuffer_rec(GUI_ENTRY_REC *entry, CUTBUFFE void gui_entry_erase(GUI_ENTRY_REC *entry, int size, CUTBUFFER_UPDATE_OP update_cutbuffer) { - size_t w = 0; + size_t i, w = 0; g_return_if_fail(entry != NULL); @@ -700,6 +834,23 @@ void gui_entry_erase(GUI_ENTRY_REC *entry, int size, CUTBUFFER_UPDATE_OP update_ g_memmove(entry->text + entry->pos - size, entry->text + entry->pos, (entry->text_len-entry->pos+1) * sizeof(unichar)); + if (entry->uses_extents) { + for (i = entry->pos - size; i < entry->pos; i++) { + if (entry->extents[i+1] != NULL) { + g_free(entry->extents[i+1]); + } + } + g_memmove(entry->extents + entry->pos - size + 1, entry->extents + entry->pos + 1, + (entry->text_len - entry->pos) * sizeof(void *)); /* no null terminator here */ + for (i = 0; i < size; i++) { + entry->extents[entry->text_len - i] = NULL; + } + if (entry->text_len == size && entry->extents[0] != NULL) { + g_free(entry->extents[0]); + entry->extents[0] = NULL; + } + } + entry->pos -= size; entry->text_len -= size; @@ -719,11 +870,28 @@ void gui_entry_erase_cell(GUI_ENTRY_REC *entry) mk_wcwidth(entry->text[entry->pos+size]) == 0) size++; g_memmove(entry->text + entry->pos, entry->text + entry->pos + size, - (entry->text_len-entry->pos-size+1) * sizeof(unichar)); + (entry->text_len-entry->pos-size+1) * sizeof(unichar)); + + if (entry->uses_extents) { + int i; + for (i = 0; i < size; i++) { + g_free(entry->extents[entry->pos + i + 1]); + } + g_memmove(entry->extents + entry->pos + 1, entry->extents + entry->pos + size + 1, + (entry->text_len-entry->pos-size) * sizeof(char *)); + for (i = 0; i < size; i++) { + entry->extents[entry->text_len - i] = NULL; + } + if (entry->text_len == size && entry->extents[0] != NULL) { + g_free(entry->extents[0]); + entry->extents[0] = NULL; + } + } entry->text_len -= size; gui_entry_redraw_from(entry, entry->pos); + gui_entry_fix_cursor(entry); gui_entry_draw(entry); } @@ -782,6 +950,7 @@ void gui_entry_erase_next_word(GUI_ENTRY_REC *entry, int to_space, CUTBUFFER_UPD void gui_entry_transpose_chars(GUI_ENTRY_REC *entry) { unichar chr; + char *extent; if (entry->pos == 0 || entry->text_len < 2) return; @@ -794,6 +963,12 @@ void gui_entry_transpose_chars(GUI_ENTRY_REC *entry) entry->text[entry->pos] = entry->text[entry->pos-1]; entry->text[entry->pos-1] = chr; + if (entry->uses_extents) { + extent = entry->extents[entry->pos+1]; + entry->extents[entry->pos+1] = entry->extents[entry->pos]; + entry->extents[entry->pos] = extent; + } + entry->pos++; gui_entry_redraw_from(entry, entry->pos-2); @@ -830,31 +1005,60 @@ void gui_entry_transpose_words(GUI_ENTRY_REC *entry) /* do wordswap if any found */ if (spos1 < epos1 && epos1 < spos2 && spos2 < epos2) { unichar *first, *sep, *second; + char **first_extent, **sep_extent, **second_extent; int i; first = (unichar *) g_malloc( (epos1 - spos1) * sizeof(unichar) ); sep = (unichar *) g_malloc( (spos2 - epos1) * sizeof(unichar) ); second = (unichar *) g_malloc( (epos2 - spos2) * sizeof(unichar) ); - for (i = spos1; i < epos1; i++) + first_extent = (char **) g_malloc( (epos1 - spos1) * sizeof(char *) ); + sep_extent = (char **) g_malloc( (spos2 - epos1) * sizeof(char *) ); + second_extent = (char **) g_malloc( (epos2 - spos2) * sizeof(char *) ); + + for (i = spos1; i < epos1; i++) { first[i-spos1] = entry->text[i]; - for (i = epos1; i < spos2; i++) + if (entry->uses_extents) + first_extent[i-spos1] = entry->extents[i+1]; + } + for (i = epos1; i < spos2; i++) { sep[i-epos1] = entry->text[i]; - for (i = spos2; i < epos2; i++) + if (entry->uses_extents) + sep_extent[i-epos1] = entry->extents[i+1]; + } + for (i = spos2; i < epos2; i++) { second[i-spos2] = entry->text[i]; + if (entry->uses_extents) + second_extent[i-spos2] = entry->extents[i+1]; + } entry->pos = spos1; - for (i = 0; i < epos2-spos2; i++) - entry->text[entry->pos++] = second[i]; - for (i = 0; i < spos2-epos1; i++) - entry->text[entry->pos++] = sep[i]; - for (i = 0; i < epos1-spos1; i++) - entry->text[entry->pos++] = first[i]; + for (i = 0; i < epos2-spos2; i++) { + entry->text[entry->pos] = second[i]; + if (entry->uses_extents) + entry->extents[entry->pos+1] = second_extent[i]; + entry->pos++; + } + for (i = 0; i < spos2-epos1; i++) { + entry->text[entry->pos] = sep[i]; + if (entry->uses_extents) + entry->extents[entry->pos+1] = sep_extent[i]; + entry->pos++; + } + for (i = 0; i < epos1-spos1; i++) { + entry->text[entry->pos] = first[i]; + if (entry->uses_extents) + entry->extents[entry->pos+1] = first_extent[i]; + entry->pos++; + } g_free(first); g_free(sep); g_free(second); + g_free(first_extent); + g_free(sep_extent); + g_free(second_extent); } gui_entry_redraw_from(entry, spos1); @@ -938,11 +1142,17 @@ void gui_entry_set_pos(GUI_ENTRY_REC *entry, int pos) void gui_entry_set_text_and_pos_bytes(GUI_ENTRY_REC *entry, const char *str, int pos_bytes) { - int pos; + int pos, extents_alloc; + char **extents; const char *ptr; g_return_if_fail(entry != NULL); + extents = entry->extents; + extents_alloc = entry->text_alloc; + entry->extents = NULL; + entry->uses_extents = FALSE; + gui_entry_set_text(entry, str); if (entry->utf8) { @@ -953,6 +1163,19 @@ void gui_entry_set_text_and_pos_bytes(GUI_ENTRY_REC *entry, const char *str, int else pos = pos_bytes; + if (extents != NULL) { + entry->uses_extents = TRUE; + entry->extents = extents; + if (extents_alloc < entry->text_alloc) { + int i; + entry->extents = g_realloc(entry->extents, + sizeof(char *) * entry->text_alloc); + for (i = extents_alloc; i < entry->text_alloc; i++) { + entry->extents[i] = NULL; + } + } + } + gui_entry_redraw_from(entry, 0); gui_entry_set_pos(entry, pos); } @@ -1042,3 +1265,234 @@ void gui_entry_redraw(GUI_ENTRY_REC *entry) gui_entry_fix_cursor(entry); gui_entry_draw(entry); } + +static void gui_entry_alloc_extents(GUI_ENTRY_REC *entry) +{ + entry->uses_extents = TRUE; + entry->extents = g_new0(char *, entry->text_alloc); +} + +void gui_entry_set_extent(GUI_ENTRY_REC *entry, int pos, const char *text) +{ + int update = FALSE; + + g_return_if_fail(entry != NULL); + + if (pos < 0 || pos > entry->text_len) + return; + + if (text == NULL) + return; + + if (!entry->uses_extents) { + gui_entry_alloc_extents(entry); + } + + if (g_strcmp0(entry->extents[pos], text) != 0) { + g_free(entry->extents[pos]); + if (*text == '\0') { + entry->extents[pos] = NULL; + } else { + entry->extents[pos] = g_strdup(text); + } + update = TRUE; + } + + if (update) { + gui_entry_redraw_from(entry, pos - 1); + gui_entry_fix_cursor(entry); + gui_entry_draw(entry); + } +} + +void gui_entry_set_extents(GUI_ENTRY_REC *entry, int pos, int len, const char *left, const char *right) +{ + int end, update = FALSE; + + g_return_if_fail(entry != NULL); + + if (pos < 0 || len < 0 || pos > entry->text_len) + return; + + end = pos + len; + + if (end > entry->text_len) + end = entry->text_len; + + if (!entry->uses_extents) { + gui_entry_alloc_extents(entry); + } + + if (g_strcmp0(entry->extents[pos], left) != 0) { + g_free(entry->extents[pos]); + if (*left == '\0') { + entry->extents[pos] = NULL; + } else { + entry->extents[pos] = g_strdup(left); + } + update = TRUE; + } + + if (pos != end && g_strcmp0(entry->extents[end], right) != 0) { + g_free(entry->extents[end]); + if (*right == '\0') { + entry->extents[end] = NULL; + } else { + entry->extents[end] = g_strdup(right); + } + update = TRUE; + } + + if (update) { + gui_entry_redraw_from(entry, pos - 1); + gui_entry_fix_cursor(entry); + gui_entry_draw(entry); + } +} + +void gui_entry_clear_extents(GUI_ENTRY_REC *entry, int pos, int len) +{ + int i, end, update = FALSE; + + g_return_if_fail(entry != NULL); + + if (pos < 0 || len < 0 || pos > entry->text_len) + return; + + end = pos + len; + + if (end > entry->text_len) + end = entry->text_len; + + if (!entry->uses_extents) { + return; + } + + for (i = pos; i <= end; i++) { + if (entry->extents[i] != NULL) { + g_free(entry->extents[i]); + entry->extents[i] = NULL; + update = TRUE; + } + } + + if (update) { + gui_entry_redraw_from(entry, pos); + gui_entry_fix_cursor(entry); + gui_entry_draw(entry); + } +} + +char *gui_entry_get_extent(GUI_ENTRY_REC *entry, int pos) +{ + g_return_val_if_fail(entry != NULL, NULL); + + if (!entry->uses_extents) + return NULL; + + if (pos < 0 || pos >= entry->text_len) + return NULL; + + return entry->extents[pos]; +} + +#define POS_FLAG "%|" +GSList *gui_entry_get_text_and_extents(GUI_ENTRY_REC *entry) +{ + GSList *list = NULL; + GString *str; + int i; + + g_return_val_if_fail(entry != NULL, NULL); + + if (entry->uses_extents && entry->extents[0] != NULL) { + if (entry->pos == 0) { + list = g_slist_prepend(list, g_strconcat(entry->extents[0], POS_FLAG, NULL)); + } else { + list = g_slist_prepend(list, g_strdup(entry->extents[0])); + } + } else { + if (entry->pos == 0) { + list = g_slist_prepend(list, g_strdup(POS_FLAG)); + } else { + list = g_slist_prepend(list, NULL); + } + } + + str = g_string_sized_new(entry->text_alloc); + for (i = 0; i < entry->text_len; i++) { + if (entry->utf8) { + g_string_append_unichar(str, entry->text[i]); + } else if (term_type == TERM_TYPE_BIG5) { + if(entry->text[i] > 0xff) + g_string_append_c(str, (entry->text[i] >> 8) & 0xff); + g_string_append_c(str, entry->text[i] & 0xff); + } else { + g_string_append_c(str, entry->text[i]); + } + if (entry->pos == i+1 || (entry->uses_extents && entry->extents[i+1] != NULL)) { + list = g_slist_prepend(list, g_strdup(str->str)); + g_string_truncate(str, 0); + if (entry->uses_extents && entry->extents[i+1] != NULL) { + if (entry->pos == i+1) { + list = g_slist_prepend(list, g_strconcat(entry->extents[i+1], POS_FLAG, NULL)); + } else { + list = g_slist_prepend(list, g_strdup(entry->extents[i+1])); + } + } else if (entry->pos == i+1) { + list = g_slist_prepend(list, g_strdup(POS_FLAG)); + } + } + } + if (str->len > 0) { + list = g_slist_prepend(list, g_strdup(str->str)); + } + list = g_slist_reverse(list); + g_string_free(str, TRUE); + + return list; +} + +void gui_entry_set_text_and_extents(GUI_ENTRY_REC *entry, GSList *list) +{ + GSList *tmp; + int pos = -1; + int is_extent = 1; + + gui_entry_set_text(entry, ""); + for (tmp = list, is_extent = TRUE; tmp != NULL; tmp = tmp->next, is_extent ^= 1) { + if (is_extent) { + char *extent; + int len; + + if (tmp->data == NULL) + continue; + + extent = g_strdup(tmp->data); + len = strlen(extent); + if (len >= strlen(POS_FLAG) && g_strcmp0(&extent[len-strlen(POS_FLAG)], POS_FLAG) == 0) { + char *tmp; + tmp = extent; + extent = g_strndup(tmp, len - strlen(POS_FLAG)); + g_free(tmp); + pos = entry->pos; + } + + if (strlen(extent) > 0) { + gui_entry_set_extent(entry, entry->pos, extent); + } + g_free(extent); + } else { + gui_entry_insert_text(entry, tmp->data); + } + } + gui_entry_set_pos(entry, pos); +} + +void gui_entry_init(void) +{ +} + +void gui_entry_deinit(void) +{ +} diff --git a/src/fe-text/gui-entry.h b/src/fe-text/gui-entry.h index 000c5f03..dff860d3 100644 --- a/src/fe-text/gui-entry.h +++ b/src/fe-text/gui-entry.h @@ -9,6 +9,7 @@ typedef struct { typedef struct { int text_len, text_alloc; /* as shorts, not chars */ unichar *text; + char **extents; GSList *kill_ring; @@ -26,6 +27,7 @@ typedef struct { unsigned int previous_append_next_kill:1; unsigned int append_next_kill:1; unsigned int yank_preceded:1; + unsigned int uses_extents:1; } GUI_ENTRY_REC; typedef enum { @@ -77,5 +79,14 @@ void gui_entry_move_words(GUI_ENTRY_REC *entry, int count, int to_space); void gui_entry_redraw(GUI_ENTRY_REC *entry); +void gui_entry_set_extent(GUI_ENTRY_REC *entry, int pos, const char *text); +void gui_entry_set_extents(GUI_ENTRY_REC *entry, int pos, int len, const char *left, const char *right); +void gui_entry_clear_extents(GUI_ENTRY_REC *entry, int pos, int len); +char *gui_entry_get_extent(GUI_ENTRY_REC *entry, int pos); +GSList *gui_entry_get_text_and_extents(GUI_ENTRY_REC *entry); +void gui_entry_set_text_and_extents(GUI_ENTRY_REC *entry, GSList *list); + +void gui_entry_init(void); +void gui_entry_deinit(void); #endif diff --git a/src/fe-text/irssi.c b/src/fe-text/irssi.c index 0288e4f1..f30ce4b8 100644 --- a/src/fe-text/irssi.c +++ b/src/fe-text/irssi.c @@ -165,6 +165,7 @@ static void textui_finish_init(void) gui_expandos_init(); gui_printtext_init(); gui_readline_init(); + gui_entry_init(); lastlog_init(); mainwindows_init(); mainwindow_activity_init(); @@ -230,6 +231,7 @@ static void textui_deinit(void) lastlog_deinit(); statusbar_deinit(); + gui_entry_deinit(); gui_printtext_deinit(); gui_readline_deinit(); gui_windows_deinit(); diff --git a/src/perl/textui/TextUI.xs b/src/perl/textui/TextUI.xs index 12732e3f..e2f162a0 100644 --- a/src/perl/textui/TextUI.xs +++ b/src/perl/textui/TextUI.xs @@ -124,6 +124,74 @@ gui_input_set(str) CODE: gui_entry_set_text(active_entry, str); +void +gui_input_set_extent(pos, text) + int pos + char *text +PREINIT: + char *tt; +CODE: + tt = text != NULL ? format_string_expand(text, NULL) : NULL; + gui_entry_set_extent(active_entry, pos, tt); + g_free(tt); + +void +gui_input_set_extents(pos, len, left, right) + int pos + int len + char *left + char *right +PREINIT: + char *tl; + char *tr; +CODE: + tl = left != NULL ? format_string_expand(left, NULL) : NULL; + tr = right != NULL ? format_string_expand(right, NULL) : NULL; + gui_entry_set_extents(active_entry, pos, len, tl, tr); + g_free(tl); + g_free(tr); + +void +gui_input_clear_extents(pos, len = 0) + int pos + int len +CODE: + gui_entry_clear_extents(active_entry, pos, len); + +void +gui_input_get_extent(pos) + int pos +PREINIT: + char *ret; +PPCODE: + ret = gui_entry_get_extent(active_entry, pos); + XPUSHs(sv_2mortal(new_pv(ret))); + g_free(ret); + +void +gui_input_get_text_and_extents() +PREINIT: + GSList *ret, *tmp; +PPCODE: + ret = gui_entry_get_text_and_extents(active_entry); + for (tmp = ret; tmp != NULL; tmp = tmp->next) { + XPUSHs(sv_2mortal(new_pv(tmp->data))); + } + g_slist_free_full(ret, g_free); + +void +gui_input_set_text_and_extents(...) +PREINIT: + GSList *list; + int i; +PPCODE: + list = NULL; + for (i = items; i > 0; i--) { + list = g_slist_prepend(list, SvPV_nolen(ST(i-1))); + } + gui_entry_set_text_and_extents(active_entry, list); + g_slist_free(list); + int gui_input_get_pos() CODE: |