elm_code: Support rendering tabs

Add a tabstop configurable value so the view can be adjusted.
shuffle all content and tokens along when a tab is encountered.
This commit is contained in:
Andy Williams 2015-03-29 20:12:28 +01:00
parent 08daaed1f5
commit e0e0eaa32c
10 changed files with 119 additions and 44 deletions

View File

@ -52,7 +52,6 @@ static void _elm_code_file_line_insert_data(Elm_Code_File *file, const char *con
line->modified[length] = 0;
line->length = length;
}
line->unicode_length = elm_code_text_unicode_strlen(content, length);
if (row == 1)
file->lines = eina_list_prepend(file->lines, line);

View File

@ -20,12 +20,6 @@ elm_code_line_free(Elm_Code_Line *line)
free(line);
}
EAPI unsigned int
elm_code_line_utf8_length_get(Elm_Code_Line *line)
{
return line->unicode_length;
}
EAPI void elm_code_line_status_set(Elm_Code_Line *line, Elm_Code_Status_Type status)
{
if (!line)

View File

@ -24,7 +24,7 @@ typedef struct _Elm_Code_Line
Elm_Code_File *file;
const char *content;
unsigned int length, unicode_length;
unsigned int length;
unsigned int number;
char *modified;
@ -37,8 +37,6 @@ typedef struct _Elm_Code_Line
EAPI void elm_code_line_free(Elm_Code_Line *line);
EAPI unsigned int elm_code_line_utf8_length_get(Elm_Code_Line *line);
/**
* @brief Line markup functions.
* @defgroup Line highlighting and status manipulation

View File

@ -106,7 +106,6 @@ _elm_code_parser_diff_trim_leading(Elm_Code_Line *line, unsigned int count)
}
line->length -= count;
line->unicode_length -= count;
}
static void

View File

@ -46,7 +46,7 @@ typedef struct
unsigned int cursor_line, cursor_col;
Eina_Bool editable, focussed;
Eina_Bool show_line_numbers;
unsigned int line_width_marker;
unsigned int line_width_marker, tabstop;
Eina_Bool show_whitespace;
Elm_Code_Widget_Selection_Data *selection;

View File

@ -36,7 +36,6 @@ elm_code_line_text_set(Elm_Code_Line *line, const char *chars, unsigned int leng
strncpy(newtext, chars, length);
line->modified = newtext;
line->length = length;
line->unicode_length = elm_code_text_unicode_strlen(line->modified, line->length);
file = line->file;
elm_code_callback_fire(file->parent, &ELM_CODE_EVENT_LINE_LOAD_DONE, line);
@ -158,7 +157,6 @@ elm_code_line_text_insert(Elm_Code_Line *line, unsigned int position, const char
line->modified = inserted;
line->length += length;
line->unicode_length = elm_code_text_unicode_strlen(line->modified, line->length);
file = line->file;
elm_code_callback_fire(file->parent, &ELM_CODE_EVENT_LINE_LOAD_DONE, line);
@ -196,7 +194,6 @@ elm_code_line_text_remove(Elm_Code_Line *line, unsigned int position, int length
line->modified = removed;
line->length -= length;
line->unicode_length = elm_code_text_unicode_strlen(line->modified, line->length);
file = line->file;
elm_code_callback_fire(file->parent, &ELM_CODE_EVENT_LINE_LOAD_DONE, line);
@ -204,24 +201,47 @@ elm_code_line_text_remove(Elm_Code_Line *line, unsigned int position, int length
/* generic text functions */
unsigned int
elm_code_text_tabwidth_at_position(unsigned int position, unsigned int tabstop)
{
return tabstop - (position % tabstop);
}
EAPI unsigned int
elm_code_text_unicode_strlen(const char *chars, unsigned int length)
elm_code_line_text_column_width_to_position(Elm_Code_Line *line, unsigned int position, unsigned int tabstop)
{
Eina_Unicode unicode;
unsigned int count = 0;
int index = 0;
const char *chars;
if (chars == NULL)
if (line->length == 0)
return 0;
while ((unsigned int) index < length)
if (line->modified)
chars = line->modified;
else
chars = line->content;
if (position > line->length)
position = line->length;
while ((unsigned int) index < position)
{
unicode = eina_unicode_utf8_next_get(chars, &index);
if (unicode == 0)
break;
count++;
if (unicode == '\t')
count += elm_code_text_tabwidth_at_position(count, tabstop);
else
count++;
}
return count;
}
EAPI unsigned int
elm_code_line_text_column_width(Elm_Code_Line *line, unsigned int tabstop)
{
return elm_code_line_text_column_width_to_position(line, line->length, tabstop);
}

View File

@ -48,7 +48,11 @@ EAPI void elm_code_line_text_remove(Elm_Code_Line *line, unsigned int position,
*
*/
EAPI unsigned int elm_code_text_unicode_strlen(const char *chars, unsigned int length);
EAPI unsigned int elm_code_text_tabwidth_at_position(unsigned int position, unsigned int tabstop);
EAPI unsigned int elm_code_line_text_column_width_to_position(Elm_Code_Line *line, unsigned int length, unsigned int tabstop);
EAPI unsigned int elm_code_line_text_column_width(Elm_Code_Line *line, unsigned int tabstop);
/**
* @}

View File

@ -51,6 +51,8 @@ _elm_code_widget_eo_base_constructor(Eo *obj, Elm_Code_Widget_Data *pd)
pd->cursor_line = 1;
pd->cursor_col = 1;
pd->tabstop = 8;
}
EOLIAN static Eo *
@ -92,6 +94,7 @@ _elm_code_widget_resize(Elm_Code_Widget *widget)
Eina_List *item;
Evas_Coord ww, wh, old_width, old_height;
int w, h, cw, ch, gutter;
unsigned int line_width;
Elm_Code_Widget_Data *pd;
pd = eo_data_scope_get(widget, ELM_CODE_WIDGET_CLASS);
@ -108,8 +111,11 @@ _elm_code_widget_resize(Elm_Code_Widget *widget)
w = 0;
h = elm_code_file_lines_get(pd->code->file);
EINA_LIST_FOREACH(pd->code->file->lines, item, line)
if ((int) line->unicode_length + gutter + 1 > w)
w = (int) line->unicode_length + gutter + 1;
{
line_width = elm_code_line_text_column_width(line, pd->tabstop);
if ((int) column_length + gutter + 1 > w)
w = (int) column_length + gutter + 1;
}
if (w*cw > ww)
ww = w*cw;
@ -156,21 +162,21 @@ static void
_elm_code_widget_fill_line_tokens(Elm_Code_Widget *widget, Evas_Textgrid_Cell *cells,
unsigned int count, Elm_Code_Line *line)
{
Elm_Code_Widget_Data *pd;
Eina_List *item;
Elm_Code_Token *token;
const char *content;
unsigned int start, end, length, offset;
unsigned int token_start_col, token_end_col;
pd = eo_data_scope_get(widget, ELM_CODE_WIDGET_CLASS);
offset = elm_code_widget_text_left_gutter_width_get(widget);
start = offset;
content = elm_code_line_text_get(line, NULL);
length = line->unicode_length + offset;
length = elm_code_line_text_column_width(line, pd->tabstop) + offset;
EINA_LIST_FOREACH(line->tokens, item, token)
{
token_start_col = elm_code_text_unicode_strlen(content, token->start - 1) + offset;
token_end_col = elm_code_text_unicode_strlen(content, token->end - 1) + offset;
token_start_col = elm_code_line_text_column_width_to_position(line, token->start - 1, pd->tabstop) + offset;
token_end_col = elm_code_line_text_column_width_to_position(line, token->end - 1, pd->tabstop) + offset;
if (token_start_col > start)
_elm_code_widget_fill_line_token(cells, count, start, token_start_col, ELM_CODE_TOKEN_TYPE_DEFAULT);
@ -235,7 +241,11 @@ _elm_code_widget_fill_whitespace(Elm_Code_Widget *widget, Eina_Unicode character
pd = eo_data_scope_get(widget, ELM_CODE_WIDGET_CLASS);
if (!pd->show_whitespace)
return;
{
if (character== '\t')
cell->codepoint = 0;
return;
}
switch (character)
{
@ -301,7 +311,7 @@ _elm_code_widget_fill_line(Elm_Code_Widget *widget, Elm_Code_Line *line)
{
char *chr;
Eina_Unicode unichr;
unsigned int length, x;
unsigned int length, x, charwidth, i;
int w, chrpos, gutter;
Evas_Textgrid_Cell *cells;
Elm_Code_Widget_Data *pd;
@ -315,17 +325,26 @@ _elm_code_widget_fill_line(Elm_Code_Widget *widget, Elm_Code_Line *line)
_elm_code_widget_fill_gutter(widget, cells, line->status, line->number);
_elm_code_widget_fill_line_tokens(widget, cells, w, line);
length = elm_code_line_utf8_length_get(line);
length = elm_code_line_text_column_width(line, pd->tabstop);
chrpos = 0;
chr = (char *)elm_code_line_text_get(line, NULL);
for (x = gutter; x < (unsigned int) w && x < length + gutter; x++)
for (x = gutter; x < (unsigned int) w && x < length + gutter; x+=charwidth)
{
unichr = eina_unicode_utf8_next_get(chr, &chrpos);
cells[x].codepoint = unichr;
cells[x].bg = _elm_code_widget_status_type_get(widget, line->status, x - gutter + 1);
charwidth = 1;
if (unichr == '\t')
charwidth = elm_code_text_tabwidth_at_position(x - gutter, pd->tabstop);
for (i = x + 1; i < x + charwidth; i++)
{
cells[i].codepoint = 0;
cells[i].bg = _elm_code_widget_status_type_get(widget, line->status, x - gutter + 1);
}
_elm_code_widget_fill_whitespace(widget, unichr, &cells[x]);
}
for (; x < (unsigned int) w; x++)
@ -459,7 +478,7 @@ _elm_code_widget_cursor_key_will_move(Elm_Code_Widget *widget, const char *key)
else if (!strcmp(key, "Left"))
return pd->cursor_col > 1;
else if (!strcmp(key, "Right"))
return pd->cursor_col < (unsigned int) line->unicode_length + 1;
return pd->cursor_col < elm_code_line_text_column_width(line, pd->tabstop) + 1;
else
return EINA_FALSE;
}
@ -586,15 +605,17 @@ _elm_code_widget_clicked_editable_cb(Elm_Code_Widget *widget, unsigned int row,
{
Elm_Code_Widget_Data *pd;
Elm_Code_Line *line;
unsigned int column_width;
pd = eo_data_scope_get(widget, ELM_CODE_WIDGET_CLASS);
line = elm_code_file_line_get(pd->code->file, row);
if (!line)
return;
column_width = elm_code_line_text_column_width(line, pd->tabstop);
if (col > line->unicode_length + 1)
col = line->unicode_length + 1;
if (col > column_width + 1)
col = column_width + 1;
else if (col <= 0)
col = 1;
@ -704,7 +725,7 @@ _elm_code_widget_cursor_move_up(Elm_Code_Widget *widget)
{
Elm_Code_Widget_Data *pd;
Elm_Code_Line *line;
unsigned int row, col;
unsigned int row, col, column_width;
pd = eo_data_scope_get(widget, ELM_CODE_WIDGET_CLASS);
row = pd->cursor_line;
@ -715,8 +736,9 @@ _elm_code_widget_cursor_move_up(Elm_Code_Widget *widget)
row--;
line = elm_code_file_line_get(pd->code->file, row);
if (col > (unsigned int) line->unicode_length + 1)
col = line->unicode_length + 1;
column_width = elm_code_line_text_column_width(line, pd->tabstop);
if (col > column_width + 1)
col = column_width + 1;
_elm_code_widget_cursor_move(widget, pd, col, row, EINA_TRUE);
}
@ -726,7 +748,7 @@ _elm_code_widget_cursor_move_down(Elm_Code_Widget *widget)
{
Elm_Code_Widget_Data *pd;
Elm_Code_Line *line;
unsigned int row, col;
unsigned int row, col, column_width;
pd = eo_data_scope_get(widget, ELM_CODE_WIDGET_CLASS);
row = pd->cursor_line;
@ -737,8 +759,9 @@ _elm_code_widget_cursor_move_down(Elm_Code_Widget *widget)
row++;
line = elm_code_file_line_get(pd->code->file, row);
if (col > (unsigned int) line->unicode_length + 1)
col = line->unicode_length + 1;
column_width = elm_code_line_text_column_width(line, pd->tabstop);
if (col > column_width + 1)
col = column_width + 1;
_elm_code_widget_cursor_move(widget, pd, col, row, EINA_TRUE);
}
@ -765,7 +788,7 @@ _elm_code_widget_cursor_move_right(Elm_Code_Widget *widget)
pd = eo_data_scope_get(widget, ELM_CODE_WIDGET_CLASS);
line = elm_code_file_line_get(pd->code->file, pd->cursor_line);
if (pd->cursor_col > (unsigned int) line->unicode_length)
if (pd->cursor_col > elm_code_line_text_column_width(line, pd->tabstop))
return;
_elm_code_widget_cursor_move(widget, pd, pd->cursor_col+1, pd->cursor_line, EINA_TRUE);
@ -918,6 +941,9 @@ _elm_code_widget_delete(Elm_Code_Widget *widget)
Elm_Code *code;
Elm_Code_Line *line;
unsigned int row, col;
Elm_Code_Widget_Data *pd;
pd = eo_data_scope_get(widget, ELM_CODE_WIDGET_CLASS);
if (_elm_code_widget_delete_selection(widget))
return;
@ -926,7 +952,7 @@ _elm_code_widget_delete(Elm_Code_Widget *widget)
code = elm_code_widget_code_get(),
elm_code_widget_cursor_position_get(&col, &row));
line = elm_code_file_line_get(code->file, row);
if (col > line->unicode_length)
if (col > elm_code_line_text_column_width(line, pd->tabstop))
{
if (row == elm_code_file_lines_get(code->file))
return;
@ -1111,6 +1137,19 @@ _elm_code_widget_gravity_get(Eo *obj EINA_UNUSED, Elm_Code_Widget_Data *pd, doub
*y = pd->gravity_y;
}
EOLIAN static void
_elm_code_widget_tabstop_set(Eo *obj EINA_UNUSED, Elm_Code_Widget_Data *pd, unsigned int tabstop)
{
pd->tabstop = tabstop;
_elm_code_widget_fill(obj);
}
EOLIAN static unsigned int
_elm_code_widget_tabstop_get(Eo *obj EINA_UNUSED, Elm_Code_Widget_Data *pd)
{
return pd->tabstop;
}
EOLIAN static void
_elm_code_widget_editable_set(Eo *obj, Elm_Code_Widget_Data *pd, Eina_Bool editable)
{

View File

@ -59,6 +59,26 @@ class Elm_Code_Widget (Elm_Layout, Elm_Interface_Atspi_Text)
double y; /*@ The vertical gravity of the widget's scroller - valid values are 0.0 and 1.0 */
}
}
tabstop {
set {
/*@
Set the width of a tab stop, used purely for visual layout of tab characters.
Recommended value is between 2 and 8.
@ingroup Layout */
}
get {
/*@
Get the current width of a tab stop.
This is used to determine where characters after a tab should appear in the line..
@ingroup Layout */
}
values {
uint tabstop; /*@ Maximum width of a tab character */
}
}
editable {
set {
/*@

View File

@ -22,6 +22,7 @@ _elm_code_widget_selection_limit(Evas_Object *widget EINA_UNUSED, Elm_Code_Widge
{
Elm_Code_Line *line;
Elm_Code_File *file;
unsigned int width;
file = pd->code->file;
@ -29,9 +30,10 @@ _elm_code_widget_selection_limit(Evas_Object *widget EINA_UNUSED, Elm_Code_Widge
*row = elm_code_file_lines_get(file);
line = elm_code_file_line_get(file, *row);
width = elm_code_line_text_column_width(line, pd->tabstop);
if (*col > line->unicode_length + 1)
*col = line->unicode_length + 1;
if (*col > width + 1)
*col = width + 1;
if (*col < 1)
*col = 1;
}