чување 7e7c9fd4c07e715b2b78b13a9243c73f3331744a
родитељ b1182c444d3807b27a56b00be640754bda63a856
Аутор: Страхиња Радић <contact@strahinja.org>
Датум: Tue, 15 Feb 2022 20:31:14 +0100
Initial selection support
Signed-off-by: Страхиња Радић <contact@strahinja.org>
Diffstat:
| M | TODO | | | 8 | +++++--- |
| M | config.def.h | | | 11 | +++++++++++ |
| M | config.h | | | 11 | +++++++++++ |
| M | draw.c | | | 121 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------------- |
| M | draw.h | | | 19 | ++++++++++++++----- |
| M | sled.c | | | 270 | +++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------------- |
| M | util.h | | | 6 | ++++-- |
измењених датотека: 7, додавања: 324(+), брисања: 122(-)
diff --git a/TODO b/TODO
@@ -3,9 +3,11 @@
[~] Create a working base by migration from poe
[x] Implement "inverse vi mode"
- [ ] Selections!
- [ ] Selections modify behavior of eg. Delete key ->
- DrawState.in_selection is needed
+ [~] Selections!
+ [x] Initial support for selections
+ (DrawState.in_selection)
+ [ ] Selections modify behavior of eg. Delete key
+ and inserting characters
[ ] Copy/paste?
diff --git a/config.def.h b/config.def.h
@@ -6,6 +6,8 @@
#define ERROR_BG TB_RED
#define PROMPT_FG TB_YELLOW | TB_BOLD
#define PROMPT_BG TB_MAGENTA
+#define SEL_FG TB_BLACK
+#define SEL_BG TB_WHITE
#define SHADOW_FG TB_BLACK
#define SHADOW_BG TB_BLACK | TB_BOLD
#define TEXT_FG TB_WHITE
@@ -36,6 +38,9 @@ int move_start(struct DrawState* state);
int move_top(struct DrawState* state);
int move_up(struct DrawState* state);
int show_help(struct DrawState* state);
+int toggle_selection(struct DrawState* state);
+
+/* clang-format off */
/* Always processed */
static const struct Key top_level_keys[] = {
@@ -70,6 +75,8 @@ static const struct Key global_keys[] = {
.callback = erase_to_end },
{ .ev = { .key = TB_KEY_CTRL_R },
.callback = move_prev_word },
+ { .ev = { .key = TB_KEY_CTRL_SPACE },
+ .callback = toggle_selection },
{ .ev = { .key = TB_KEY_CTRL_T },
.callback = move_next_word },
{ .ev = { .key = TB_KEY_CTRL_U },
@@ -105,11 +112,13 @@ static const struct Key command_keys[] = {
{ .ev = { .ch = 'k' }, .callback = move_up },
{ .ev = { .ch = 'l' }, .callback = move_right },
{ .ev = { .ch = 'q' }, .callback = exit_program },
+ { .ev = { .ch = 'v' }, .callback = toggle_selection },
{ .ev = { .ch = 'w' }, .callback = move_next_word },
{ .ev = { .ch = 'G' }, .callback = move_bottom },
{ .ev = { .ch = 'H' }, .callback = show_help },
{ .ev = { .ch = 'W' }, .callback = move_prev_word }
};
+/* clang-format on */
void format_filename(char* result, size_t result_size, const char* format,
const struct DrawState* state);
@@ -118,6 +127,7 @@ void format_mode(char* result, size_t result_size, const char* format,
void format_position(char* result, size_t result_size, const char* format,
const struct DrawState* state);
+/* clang-format off */
static const struct StatusSegment status_segments[] = {
{.format = "%s%s",
.callback = format_filename,
@@ -140,3 +150,4 @@ static const struct StatusSegment status_segments[] = {
.bg = TB_DEFAULT,
.alignment = RIGHT},
};
+/* clang-format on */
diff --git a/config.h b/config.h
@@ -6,6 +6,8 @@
#define ERROR_BG TB_RED
#define PROMPT_FG TB_YELLOW | TB_BOLD
#define PROMPT_BG TB_MAGENTA
+#define SEL_FG TB_BLACK
+#define SEL_BG TB_WHITE
#define SHADOW_FG TB_BLACK
#define SHADOW_BG TB_BLACK | TB_BOLD
#define TEXT_FG TB_WHITE
@@ -36,6 +38,9 @@ int move_start(struct DrawState* state);
int move_top(struct DrawState* state);
int move_up(struct DrawState* state);
int show_help(struct DrawState* state);
+int toggle_selection(struct DrawState* state);
+
+/* clang-format off */
/* Always processed */
static const struct Key top_level_keys[] = {
@@ -70,6 +75,8 @@ static const struct Key global_keys[] = {
.callback = erase_to_end },
{ .ev = { .key = TB_KEY_CTRL_R },
.callback = move_prev_word },
+ { .ev = { .key = TB_KEY_CTRL_SPACE },
+ .callback = toggle_selection },
{ .ev = { .key = TB_KEY_CTRL_T },
.callback = move_next_word },
{ .ev = { .key = TB_KEY_CTRL_U },
@@ -105,11 +112,13 @@ static const struct Key command_keys[] = {
{ .ev = { .ch = 'k' }, .callback = move_up },
{ .ev = { .ch = 'l' }, .callback = move_right },
{ .ev = { .ch = 'q' }, .callback = exit_program },
+ { .ev = { .ch = 'v' }, .callback = toggle_selection },
{ .ev = { .ch = 'w' }, .callback = move_next_word },
{ .ev = { .ch = 'G' }, .callback = move_bottom },
{ .ev = { .ch = 'H' }, .callback = show_help },
{ .ev = { .ch = 'W' }, .callback = move_prev_word }
};
+/* clang-format on */
void format_filename(char* result, size_t result_size, const char* format,
const struct DrawState* state);
@@ -118,6 +127,7 @@ void format_mode(char* result, size_t result_size, const char* format,
void format_position(char* result, size_t result_size, const char* format,
const struct DrawState* state);
+/* clang-format off */
static const struct StatusSegment status_segments[] = {
{.format = "%s%s",
.callback = format_filename,
@@ -140,3 +150,4 @@ static const struct StatusSegment status_segments[] = {
.bg = TB_DEFAULT,
.alignment = RIGHT},
};
+/* clang-format on */
diff --git a/draw.c b/draw.c
@@ -14,25 +14,28 @@
/* clang-format off */
static const char* help_title = "sled help";
static const char* help[] = {
- "Esc - Close dialog, clear error",
- "F1 - Show this screen",
- "C-C - Switch command <-> insert mode",
- "Home or C-A - Go to start of line",
- "PgUp or C-B - Go to previous page",
- "PgDown or C-F - Go to next page",
- "End or C-E - Go to end of line",
- "C-Q - Quit",
+ "Esc - Close dialog, clear error, cancel",
+ " selection",
+ "F1 - Show this screen",
+ "C-C - Switch command <-> insert mode",
+ "Home or C-A - Go to start of line",
+ "PgUp or C-B - Go to previous page",
+ "PgDown or C-F - Go to next page",
+ "End or C-E - Go to end of line",
+ "C-Space - Toggle selection mode",
+ "C-Q - Quit",
"",
- "Arrow keys work both in insert and command mode.",
- "Some vi-like keys work in command mode.",
+ "Arrow keys work in insert, selection and command modes.",
+ "Some vi-like keys work in command and selection modes.",
"",
"See the manual (man sled) for full help."};
const char* mode_labels[] = {
- [UNKNOWN_MODE] = "UNKNOWN",
- [COMMAND_MODE] = "COMMAND",
- [HELP_MODE] = "HELP",
- [INSERT_MODE] = "INSERT",
- [PROMPT_MODE] = "PROMPT"
+ [UNKNOWN_MODE] = "UNKNOWN",
+ [COMMAND_MODE] = "COMMAND",
+ [HELP_MODE] = "HELP",
+ [INSERT_MODE] = "INSERT",
+ [PROMPT_MODE] = "PROMPT",
+ [SELECTION_MODE] = "SELECTION"
};
const char* errors[] = {
[ERR_UNKNOWN_KEY] = "Unknown key (press F1 for help)",
@@ -94,7 +97,12 @@ init_drawstate(struct DrawState* state, char* error, char* filename,
state->dirty = 0;
state->in_prompt = 0;
state->in_command_mode = 0;
+ state->in_selection_mode = 0;
state->show_help = 0;
+ state->sel_start_row = 0;
+ state->sel_start_col = 0;
+ state->sel_end_row = 0;
+ state->sel_end_col = 0;
}
void
@@ -209,19 +217,25 @@ draw_box(const int startx, const int endx, const int starty, const int endy,
* srch - search string; if empty or NULL no highlighting happens
* sfg - fg color of search highlght
* sbg - bg color of search highlight
+ * ssi - selection start index (>=)
+ * sei - selection end index (<)
+ * slfg - selection fg color
+ * slbg - selection bg color
* */
const char*
draw_string(const int x, const int y, const uint16_t fg, const uint16_t bg,
const char* s, const int mc, const int fc, const int p_l, const int p_r,
const Alignment align, const int ds, const int fill,
- const uint32_t* srch, const uint16_t sfg, const uint16_t sbg)
+ const uint32_t* srch, const uint16_t sfg, const uint16_t sbg,
+ const size_t ssi, const size_t sei, const uint16_t slfg,
+ const uint16_t slbg)
{
uint32_t* us = calloc(strlen(s) + 1, sizeof(uint32_t));
if (!us)
return NULL;
u8_string_to_unicode(us, s, mc);
u32_draw_string(x, y, fg, bg, us, mc, fc, p_l, p_r, align, ds, fill,
- srch, sfg, sbg);
+ srch, sfg, sbg, ssi, sei, slfg, slbg);
free(us);
return s;
}
@@ -237,12 +251,18 @@ draw_string(const int x, const int y, const uint16_t fg, const uint16_t bg,
* srch - search string; if empty or NULL no highlighting happens
* sfg - fg color of search highlght
* sbg - bg color of search highlight
+ * ssi - selection start index (>=)
+ * sei - selection end index (<)
+ * slfg - selection fg color
+ * slbg - selection bg color
* */
void
u32_draw_string(const int x, const int y, const uint16_t fg, const uint16_t bg,
const uint32_t* s, const int mc, const int fc, const int p_l,
const int p_r, const Alignment align, const int ds, const int fill,
- const uint32_t* srch, const uint16_t sfg, const uint16_t sbg)
+ const uint32_t* srch, const uint16_t sfg, const uint16_t sbg,
+ const size_t ssi, const size_t sei, const uint16_t slfg,
+ const uint16_t slbg)
{
/*
* <-------- visible part ---------->
@@ -318,6 +338,12 @@ u32_draw_string(const int x, const int y, const uint16_t fg, const uint16_t bg,
* */
while (ps && *ps && sc < c)
{
+ if ((ps - s >= ssi) && (ps - s < sei))
+ {
+ cfg = slfg;
+ cbg = slbg;
+ }
+
if (srch && *srch && hctl == 0)
{
if (u32_starts_with(ps, srch))
@@ -458,13 +484,13 @@ draw_help(const struct DrawState* state)
draw_box(startx, endx, starty, endy, DLG_FG, DLG_BG);
if (!draw_string(startx, starty, TITLE_FG, TITLE_BG, help_title,
strlen(help_title) + 2, w - 2, 1, 1, CENTER, 0, 0, NULL, 0,
- 0))
+ 0, 0, 0, 0, 0))
return NULL;
while (row < LEN(help))
{
if (!draw_string(startx + 1, starty + 1 + row, DLG_FG, DLG_BG,
help[row], w - 2, w - 2, 1, 1, LEFT, 0, 1, NULL, 0,
- 0))
+ 0, 0, 0, 0, 0))
return NULL;
row++;
}
@@ -478,6 +504,15 @@ draw_screen(const struct DrawState* state)
int max_screen_lines = state->maxy - 1;
int cy = 0;
size_t i = state->first_shown_row;
+ /* Selection start/end index - passed to u32_draw_string */
+ size_t ssi = 0;
+ size_t sei = 0;
+ /* Selection start row/col */
+ size_t ssr = 0;
+ size_t ssc = 0;
+ /* Selection end row/col */
+ size_t ser = 0;
+ size_t sec = 0;
if (!state)
return NULL;
@@ -490,10 +525,46 @@ draw_screen(const struct DrawState* state)
{
current = state->buffer + i;
+ ssi = 0;
+ sei = 0;
+
+ if (state->sel_start_row < state->sel_end_row)
+ {
+ ssr = state->sel_start_row;
+ ssc = state->sel_start_col;
+ ser = state->sel_end_row;
+ sec = state->sel_end_col;
+ }
+ else /* Swap */
+ {
+ ssr = state->sel_end_row;
+ ssc = state->sel_end_col;
+ ser = state->sel_start_row;
+ sec = state->sel_start_col;
+ }
+ if ((i > ssr) && (i < ser))
+ {
+ ssi = 0;
+ sei = current->length;
+ }
+ else
+ {
+ if (i == ssr)
+ {
+ ssi = ssc;
+ if (i != ser)
+ sei = current->length;
+ }
+ if (i == ser)
+ {
+ sei = sec;
+ }
+ }
+
if (current->text)
u32_draw_string(0, cy, TEXT_FG, TEXT_BG, current->text,
state->maxx, state->maxx, 0, 0, CENTER, 0, 0,
- NULL, 0, 0);
+ NULL, 0, 0, ssi, sei, SEL_FG, SEL_BG);
i++;
cy++;
}
@@ -519,14 +590,15 @@ draw_status(const struct DrawState* state)
{
if (!draw_string(0, state->maxy - 1, PROMPT_FG, PROMPT_BG,
state->prompt, strlen(state->prompt) + 2,
- state->maxx, 1, 1, CENTER, 0, 1, NULL, 0, 0))
+ state->maxx, 1, 1, CENTER, 0, 1, NULL, 0, 0, 0, 0,
+ 0, 0))
return NULL;
}
else if (state->error && state->error[0])
{
if (!draw_string(0, state->maxy - 1, ERROR_FG, ERROR_BG,
state->error, strlen(state->error) + 2, state->maxx,
- 1, 1, CENTER, 0, 1, NULL, 0, 0))
+ 1, 1, CENTER, 0, 1, NULL, 0, 0, 0, 0, 0, 0))
return NULL;
}
else
@@ -547,7 +619,8 @@ draw_status(const struct DrawState* state)
pseg->fg, pseg->bg, buf,
MIN(seg_size, strlen(buf) + 2),
last ? seg_size + 1 : seg_size, 1, 1,
- pseg->alignment, 0, 1, NULL, 0, 0))
+ pseg->alignment, 0, 1, NULL, 0, 0, 0, 0, 0,
+ 0))
return NULL;
pseg++;
current_start += seg_size;
diff --git a/draw.h b/draw.h
@@ -10,9 +10,9 @@
#define BORDER_VER ((uint32_t)L'\u2502')
#define BORDER_HOR ((uint32_t)L'\u2500')
-#define HELP_WIDTH 60
-#define HELP_HEIGHT 21
-#define TAB_SIZE 8
+#define HELP_WIDTH 60
+#define HELP_HEIGHT 21
+#define TAB_SIZE 8
typedef enum { LEFT, CENTER, RIGHT } Alignment;
@@ -44,9 +44,14 @@ struct DrawState {
int dirty;
int in_prompt;
int in_command_mode;
+ int in_selection_mode;
int show_help;
int maxx;
int maxy;
+ size_t sel_start_row;
+ size_t sel_start_col;
+ size_t sel_end_row;
+ size_t sel_end_col;
};
struct Key {
@@ -78,12 +83,16 @@ const char* draw_string(const int x, const int y, const uint16_t fg,
const uint16_t bg, const char* s, const int max_cols,
const int fill_cols, const int padding_left, const int padding_right,
const Alignment align, const int ds, const int fill,
- const uint32_t* srch, const uint16_t sfg, const uint16_t sbg);
+ const uint32_t* srch, const uint16_t sfg, const uint16_t sbg,
+ const size_t ssi, const size_t sei, const uint16_t slfg,
+ const uint16_t slbg);
void u32_draw_string(const int x, const int y, const uint16_t fg,
const uint16_t bg, const uint32_t* s, const int max_cols,
const int fill_cols, const int padding_left, const int padding_right,
const Alignment align, const int ds, const int fill,
- const uint32_t* srch, const uint16_t sfg, const uint16_t sbg);
+ const uint32_t* srch, const uint16_t sfg, const uint16_t sbg,
+ const size_t ssi, const size_t sei, const uint16_t slfg,
+ const uint16_t slbg);
const struct DrawState* draw_help(const struct DrawState* state);
const struct DrawState* draw_screen(const struct DrawState* state);
const struct DrawState* draw_status(const struct DrawState* state);
diff --git a/sled.c b/sled.c
@@ -59,6 +59,8 @@ int save_file(struct DrawState* state);
struct DrawState* insert_line(struct DrawState* state);
struct DrawState* join_lines(struct DrawState* state, size_t first_line,
int forward);
+int toggle_selection(struct DrawState* state);
+int clear_selection(struct DrawState* state);
void handle_editbox_key_event(struct tb_event* ev, struct DrawState* state);
void handle_key_event(struct tb_event* ev, struct DrawState* state);
void handle_search_key_event(struct tb_event* ev, struct DrawState* state);
@@ -111,11 +113,13 @@ format_mode(char* result, size_t result_size, const char* format,
mode_label = mode_labels[HELP_MODE];
else if (state->in_prompt)
mode_label = mode_labels[PROMPT_MODE];
+ else if (state->in_selection_mode)
+ mode_label = mode_labels[SELECTION_MODE];
else if (state->in_command_mode)
mode_label = mode_labels[COMMAND_MODE];
else
mode_label = mode_labels[INSERT_MODE];
-
+
snprintf(result, result_size, format, mode_label);
}
@@ -332,6 +336,11 @@ move_up(struct DrawState* state)
= state->display_column - state->maxx + 1;
state->display_column = display_length(state,
state->buffer[state->row].text, state->column);
+ if (state->in_selection_mode)
+ {
+ state->sel_end_row = state->row;
+ state->sel_end_col = state->column;
+ }
return 0;
}
@@ -359,6 +368,11 @@ move_down(struct DrawState* state)
= state->display_column - state->maxx + 1;
state->display_column = display_length(state,
state->buffer[state->row].text, state->column);
+ if (state->in_selection_mode)
+ {
+ state->sel_end_row = state->row;
+ state->sel_end_col = state->column;
+ }
return 0;
}
@@ -367,6 +381,11 @@ move_top(struct DrawState* state)
{
state->row = 0;
state->first_shown_row = 0;
+ if (state->in_selection_mode)
+ {
+ state->sel_end_row = state->row;
+ state->sel_end_col = state->column;
+ }
return 0;
}
@@ -376,6 +395,11 @@ move_start(struct DrawState* state)
state->column = 0;
state->display_column = 0;
state->first_shown_column = 0;
+ if (state->in_selection_mode)
+ {
+ state->sel_end_row = state->row;
+ state->sel_end_col = state->column;
+ }
return 0;
}
@@ -394,6 +418,11 @@ move_left(struct DrawState* state)
if (state->display_column < state->first_shown_column)
state->first_shown_column = state->display_column;
+ if (state->in_selection_mode)
+ {
+ state->sel_end_row = state->row;
+ state->sel_end_col = state->column;
+ }
return 0;
}
@@ -414,6 +443,11 @@ move_right(struct DrawState* state)
if (state->display_column - state->first_shown_column > state->maxx - 1)
state->first_shown_column
= state->display_column - state->maxx + 1;
+ if (state->in_selection_mode)
+ {
+ state->sel_end_row = state->row;
+ state->sel_end_col = state->column;
+ }
return 0;
}
@@ -436,6 +470,11 @@ move_prev_word(struct DrawState* state)
state->buffer[state->row].text, state->column);
if (state->display_column < state->first_shown_column)
state->first_shown_column = state->display_column;
+ if (state->in_selection_mode)
+ {
+ state->sel_end_row = state->row;
+ state->sel_end_col = state->column;
+ }
return 0;
}
@@ -456,6 +495,11 @@ move_next_word(struct DrawState* state)
if (state->display_column - state->first_shown_column > state->maxx - 1)
state->first_shown_column
= state->display_column - state->maxx + 1;
+ if (state->in_selection_mode)
+ {
+ state->sel_end_row = state->row;
+ state->sel_end_col = state->column;
+ }
return 0;
}
@@ -504,6 +548,11 @@ move_bottom(struct DrawState* state)
state->row = state->rows_count - 1;
state->first_shown_row
= state->row > state->maxy ? state->row - state->maxy + 2 : 0;
+ if (state->in_selection_mode)
+ {
+ state->sel_end_row = state->row;
+ state->sel_end_col = state->column;
+ }
return 0;
}
@@ -521,6 +570,11 @@ move_end(struct DrawState* state)
state->first_shown_column = dlen - state->maxx + 4;
else
state->first_shown_column = 0;
+ if (state->in_selection_mode)
+ {
+ state->sel_end_row = state->row;
+ state->sel_end_col = state->column;
+ }
return 0;
}
@@ -536,6 +590,11 @@ move_page_up(struct DrawState* state)
}
else
move_top(state);
+ if (state->in_selection_mode)
+ {
+ state->sel_end_row = state->row;
+ state->sel_end_col = state->column;
+ }
return 0;
}
@@ -551,6 +610,11 @@ move_page_down(struct DrawState* state)
}
else
move_bottom(state);
+ if (state->in_selection_mode)
+ {
+ state->sel_end_row = state->row;
+ state->sel_end_col = state->column;
+ }
return 0;
}
@@ -573,17 +637,14 @@ insert_char(struct DrawState* state, uint32_t ch)
if (state->column == MAXBUFLINE)
state->column = MAXBUFLINE - 1;
state->display_column = display_length(state,
- state->buffer[state->row].text,
- state->column);
- if (state->display_column -
- state->first_shown_column > state->maxx - 1)
+ state->buffer[state->row].text, state->column);
+ if (state->display_column - state->first_shown_column
+ > state->maxx - 1)
{
state->first_shown_column
- = state->display_column
- - state->maxx + 1;
+ = state->display_column - state->maxx + 1;
state->display_column = display_length(state,
- state->buffer[state->row].text,
- state->column);
+ state->buffer[state->row].text, state->column);
}
if (add_null)
buffer_line->text[state->column] = 0;
@@ -595,12 +656,16 @@ insert_char(struct DrawState* state, uint32_t ch)
int
insert_space(struct DrawState* state)
{
+ // TODO: Replace selection
+ clear_selection(state);
return insert_char(state, ' ');
}
int
insert_tab(struct DrawState* state)
{
+ // TODO: Replace selection
+ clear_selection(state);
return insert_char(state, '\t');
}
@@ -630,12 +695,9 @@ erase_backwards(struct DrawState* state)
state->first_shown_column--;
}
state->display_column = display_length(state,
- state->buffer[state->row].text,
- state->column);
- if (state->display_column
- < state->first_shown_column)
- state->first_shown_column
- = state->display_column;
+ state->buffer[state->row].text, state->column);
+ if (state->display_column < state->first_shown_column)
+ state->first_shown_column = state->display_column;
state->dirty = 1;
}
else if (state->row > 0)
@@ -683,12 +745,11 @@ erase_to_start(struct DrawState* state)
size_t len = buffer_line->length;
do
{
- buffer_line->text[i - state->column]
- = buffer_line->text[i];
+ buffer_line->text[i - state->column] = buffer_line->text[i];
i++;
} while (buffer_line->text[i]);
buffer_line->text[len - state->column] = 0;
- buffer_line->length = len - state->column;
+ buffer_line->length = len - state->column;
move_start(state);
state->dirty = 1;
return 0;
@@ -697,9 +758,9 @@ erase_to_start(struct DrawState* state)
int
erase_to_end(struct DrawState* state)
{
- struct BufferLine* buffer_line = &state->buffer[state->row];
+ struct BufferLine* buffer_line = &state->buffer[state->row];
buffer_line->text[state->column] = 0;
- buffer_line->length = state->column;
+ buffer_line->length = state->column;
move_end(state);
state->dirty = 1;
return 0;
@@ -720,27 +781,24 @@ insert_line(struct DrawState* state)
if (!newtext)
return NULL;
state->buffer[state->rows_count - 1].text = newtext;
- for (size_t i = state->rows_count - 1; i > state->row + 1;
- i--)
+ for (size_t i = state->rows_count - 1; i > state->row + 1; i--)
{
- u32_strncpy(state->buffer[i].text,
- state->buffer[i - 1].text, MAXBUFLINE);
- state->buffer[i].length
- = state->buffer[i - 1].length;
+ u32_strncpy(state->buffer[i].text, state->buffer[i - 1].text,
+ MAXBUFLINE);
+ state->buffer[i].length = state->buffer[i - 1].length;
}
u32_strncpy(state->buffer[state->row + 1].text,
- state->buffer[state->row].text +
- state->column, MAXBUFLINE); state->buffer[state->row +
- 1].length = u32_strlen(state->buffer[state->row + 1].text);
+ state->buffer[state->row].text + state->column, MAXBUFLINE);
+ state->buffer[state->row + 1].length
+ = u32_strlen(state->buffer[state->row + 1].text);
state->buffer[state->row].text[state->column] = 0;
state->buffer[state->row].length
= u32_strlen(state->buffer[state->row].text);
state->row++;
if (state->row
- > state->first_shown_row + (state->maxy - 1) / 2) // TODO
- state->first_shown_row
- = state->row - (state->maxy - 1) / 2;
+ > state->first_shown_row + (state->maxy - 1) / 2) // TODO
+ state->first_shown_row = state->row - (state->maxy - 1) / 2;
move_start(state);
state->dirty = 1;
return state;
@@ -752,10 +810,9 @@ join_lines(struct DrawState* state, size_t first_line, int forward)
if (!state)
return NULL;
- state->column = state->buffer[first_line].length;
+ state->column = state->buffer[first_line].length;
state->display_column = display_length(state,
- state->buffer[state->row].text,
- state->column);
+ state->buffer[state->row].text, state->column);
u32_strncat(state->buffer[first_line].text,
state->buffer[first_line + 1].text, MAXBUFLINE);
state->buffer[first_line].length
@@ -768,10 +825,9 @@ join_lines(struct DrawState* state, size_t first_line, int forward)
}
for (size_t i = first_line + 1; i < state->rows_count - 1; i++)
{
- u32_strncpy(state->buffer[i].text,
- state->buffer[i + 1].text, MAXBUFLINE);
- state->buffer[i].length
- = state->buffer[i + 1].length;
+ u32_strncpy(state->buffer[i].text, state->buffer[i + 1].text,
+ MAXBUFLINE);
+ state->buffer[i].length = state->buffer[i + 1].length;
}
free_bufferline(state->buffer + state->rows_count - 1);
state->rows_count--;
@@ -780,7 +836,7 @@ join_lines(struct DrawState* state, size_t first_line, int forward)
if (!newbuf)
return NULL;
state->buffer = newbuf;
- state->dirty = 1;
+ state->dirty = 1;
return state;
}
@@ -790,16 +846,18 @@ cancel_close(struct DrawState* state)
if (!state)
return 1;
- if (!*state->error && !state->in_prompt && !state->show_help)
+ if (!*state->error && !state->in_prompt && !state->show_help
+ && !state->in_selection_mode)
strcpy(state->error, errors[ERR_EXIT_KEY]);
- else
- {
- *state->error = 0;
+ else
+ {
+ *state->error = 0;
*state->prompt = 0;
state->in_prompt = 0;
+ clear_selection(state);
state->show_help = 0;
}
-
+
return 0;
}
@@ -844,6 +902,38 @@ show_help(struct DrawState* state)
return 0;
}
+int
+toggle_selection(struct DrawState* state)
+{
+ state->in_selection_mode = !state->in_selection_mode;
+ if (state->in_selection_mode)
+ {
+ state->sel_start_row = state->row;
+ state->sel_start_col = state->column;
+ state->sel_end_row = state->row;
+ state->sel_end_col = state->column;
+ }
+ else
+ {
+ state->sel_end_row = state->row;
+ state->sel_end_col = state->column;
+ }
+ return 0;
+}
+
+int
+clear_selection(struct DrawState* state)
+{
+ if (!state)
+ return 1;
+ state->in_selection_mode = 0;
+ state->sel_start_row = 0;
+ state->sel_start_col = 0;
+ state->sel_end_row = 0;
+ state->sel_end_col = 0;
+ return 0;
+}
+
void
handle_editbox_key_event(struct tb_event* ev, struct DrawState* state)
{
@@ -911,6 +1001,7 @@ handle_editbox_key_event(struct tb_event* ev, struct DrawState* state)
void
handle_key_event(struct tb_event* ev, struct DrawState* state)
{
+ const struct Key* current = NULL;
if (!state)
return;
@@ -930,13 +1021,13 @@ handle_key_event(struct tb_event* ev, struct DrawState* state)
state->saved_column = -1;
for (int key = 0; key < LEN(top_level_keys); key++)
- if ((top_level_keys[key].ev.key
- && (top_level_keys[key].ev.key == ev->key))
- || (top_level_keys[key].ev.ch
- && (top_level_keys[key].ev.ch == ev->ch)))
- if (top_level_keys[key].callback
- && !top_level_keys[key].callback(state))
+ {
+ current = &top_level_keys[key];
+ if (((current->ev.key == ev->key) && !ev->ch)
+ || (current->ev.ch && (current->ev.ch == ev->ch)))
+ if (current->callback && !current->callback(state))
return;
+ }
if (state->in_prompt)
return;
@@ -948,37 +1039,43 @@ handle_key_event(struct tb_event* ev, struct DrawState* state)
}
for (int key = 0; key < LEN(global_keys); key++)
- if ((global_keys[key].ev.key
- && (global_keys[key].ev.key == ev->key))
- || (global_keys[key].ev.ch
- && (global_keys[key].ev.ch == ev->ch)))
- if (global_keys[key].callback
- && !global_keys[key].callback(state))
+ {
+ current = &global_keys[key];
+ if (((current->ev.key == ev->key) && !ev->ch)
+ || (current->ev.ch && (current->ev.ch == ev->ch)))
+ if (current->callback && !current->callback(state))
return;
+ }
if (state->in_command_mode)
{
for (int key = 0; key < LEN(command_keys); key++)
- if ((command_keys[key].ev.key
- && (command_keys[key].ev.key == ev->key))
- || (command_keys[key].ev.ch
- && (command_keys[key].ev.ch == ev->ch)))
- if (command_keys[key].callback
- && !command_keys[key].callback(state))
+ {
+ current = &command_keys[key];
+ if (((current->ev.key == ev->key) && !ev->ch)
+ || (current->ev.ch
+ && (current->ev.ch == ev->ch)))
+ if (current->callback
+ && !current->callback(state))
return;
+ }
}
else
{
for (int key = 0; key < LEN(insert_keys); key++)
- if ((insert_keys[key].ev.key
- && (insert_keys[key].ev.key == ev->key))
- || (insert_keys[key].ev.ch
- && (insert_keys[key].ev.ch == ev->ch)))
- if (insert_keys[key].callback
- && !insert_keys[key].callback(state))
+ {
+ current = &insert_keys[key];
+ if (((current->ev.key == ev->key) && !ev->ch)
+ || (current->ev.ch
+ && (current->ev.ch == ev->ch)))
+ if (current->callback
+ && !current->callback(state))
return;
+ }
if (ev->ch)
{
+ // TODO: Replace selection
+ clear_selection(state);
insert_char(state, ev->ch);
return;
}
@@ -1081,24 +1178,17 @@ handle_search_key_event(struct tb_event* ev, struct DrawState* state)
erase_search_prev_word(state);
else if (ev->key == TB_KEY_DELETE)
erase_search_forward(state);
- else if (ev->key == TB_KEY_END || ev->key == TB_KEY_CTRL_E)
- move_search_end(state);
- else if (ev->key == TB_KEY_ENTER)
- hide_search(state);
- else if (ev->key == TB_KEY_ESC)
- cancel_search(state);
- else if (ev->key == TB_KEY_F3)
- next_match(state);
- else if (ev->key == TB_KEY_F4)
+ else if (ev->key == TB_KEY_END || ev->key ==
+ TB_KEY_CTRL_E) move_search_end(state); else if (ev->key ==
+ TB_KEY_ENTER) hide_search(state); else if (ev->key ==
+ TB_KEY_ESC) cancel_search(state); else if (ev->key ==
+ TB_KEY_F3) next_match(state); else if (ev->key == TB_KEY_F4)
prev_match(state);
- else if (ev->key == TB_KEY_HOME || ev->key == TB_KEY_CTRL_A)
- move_search_start(state);
- else if (ev->key == TB_KEY_SPACE)
- insert_search_char(state, ' ');
- else if (ev->key == TB_KEY_TAB)
- insert_search_char(state, '\t');
- else if (ev->ch != 0)
- insert_search_char(state, ev->ch);
+ else if (ev->key == TB_KEY_HOME || ev->key ==
+ TB_KEY_CTRL_A) move_search_start(state); else if (ev->key ==
+ TB_KEY_SPACE) insert_search_char(state, ' '); else if
+ (ev->key == TB_KEY_TAB) insert_search_char(state, '\t'); else
+ if (ev->ch != 0) insert_search_char(state, ev->ch);
*/
}
@@ -1162,8 +1252,12 @@ main(int argc, char** argv)
}
tb_init();
- *error = 0;
- state.maxx = 0;
+ *error = 0;
+ state.maxx = 0;
+ state.sel_start_row = 1;
+ state.sel_start_col = 3;
+ state.sel_end_row = 1;
+ state.sel_end_col = 6;
while (state.running)
{
diff --git a/util.h b/util.h
@@ -10,7 +10,8 @@ enum {
COMMAND_MODE,
HELP_MODE,
INSERT_MODE,
- PROMPT_MODE
+ PROMPT_MODE,
+ SELECTION_MODE
};
enum {
@@ -34,7 +35,8 @@ enum {
#define MSGDELTA 1024
#define MAXPATH 1024
/* maximum chars for UTF-8 representations of Unicode chars, per Unicode char */
-#define UTF8REPMAX 6
+#define UTF8REPMAX 6
+#define TB_KEY_CTRL_SPACE 0x00
size_t u8_string_to_unicode(uint32_t* us, const char* s, const size_t max);
size_t unicode_string_to_u8(char* s, const uint32_t* us, const size_t max);