forked from enlightenment/efl
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:
parent
08daaed1f5
commit
e0e0eaa32c
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
/**
|
||||
* @}
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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 {
|
||||
/*@
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue