1
0
mirror of https://github.com/weechat/weechat.git synced 2026-07-01 15:26:37 +02:00

core: Implement commands for operating on a single input line

This changes the commands delete_beginning_of_line, delete_end_of_line,
delete_line, move_beginning_of_line and move_end_of_line to operate on
the current line instead of the whole input. The commands
delete_beginning_of_input, delete_end_of_input, delete_input,
move_beginning_of_input and move_end_of_input are added with the
previous implementations that the line commands had.

Additionally, the commands move_previous_line and move_next_line are
added which moves the cursor to the previous/next line and keeps the
horizontal position in the line.

The meta-r key is changed from delete_line to delete_input to keep the
behavior, and because you probably want to delete the whole input more
often than the line. The meta-R key is added for delete_line.

The home, end, ctrl-u and ctrl-k keys are kept to the same commands,
which means that they change behaviour. This is because having them
operate on the line is consistent with other applications (vim, zsh),
and I also think it's more practical.

These new bindings are added:

    shift-home:  /input move_beginning_of_input
    shift-end:   /input move_end_of_input
    shift-up:    /input move_previous_line
    shift-down:  /input move_next_line
    meta-R:      /input delete_line
    meta-ctrl-u: /input delete_beginning_of_input
    meta-ctrl-k: /input delete_end_of_input

Relates to #1498
This commit is contained in:
Trygve Aaberge
2020-05-12 23:06:39 +02:00
committed by Sébastien Helleu
parent 20cea84917
commit 9ac30381fa
7 changed files with 407 additions and 16 deletions
+29 -3
View File
@@ -3481,16 +3481,26 @@ COMMAND_CALLBACK(input)
gui_input_delete_next_word (buffer);
else if (string_strcmp (argv[1], "delete_beginning_of_line") == 0)
gui_input_delete_beginning_of_line (buffer);
else if (string_strcmp (argv[1], "delete_beginning_of_input") == 0)
gui_input_delete_beginning_of_input (buffer);
else if (string_strcmp (argv[1], "delete_end_of_line") == 0)
gui_input_delete_end_of_line (buffer);
else if (string_strcmp (argv[1], "delete_end_of_input") == 0)
gui_input_delete_end_of_input (buffer);
else if (string_strcmp (argv[1], "delete_line") == 0)
gui_input_delete_line (buffer);
else if (string_strcmp (argv[1], "delete_input") == 0)
gui_input_delete_input (buffer);
else if (string_strcmp (argv[1], "transpose_chars") == 0)
gui_input_transpose_chars (buffer);
else if (string_strcmp (argv[1], "move_beginning_of_line") == 0)
gui_input_move_beginning_of_line (buffer);
else if (string_strcmp (argv[1], "move_beginning_of_input") == 0)
gui_input_move_beginning_of_input (buffer);
else if (string_strcmp (argv[1], "move_end_of_line") == 0)
gui_input_move_end_of_line (buffer);
else if (string_strcmp (argv[1], "move_end_of_input") == 0)
gui_input_move_end_of_input (buffer);
else if (string_strcmp (argv[1], "move_previous_char") == 0)
gui_input_move_previous_char (buffer);
else if (string_strcmp (argv[1], "move_next_char") == 0)
@@ -3499,6 +3509,10 @@ COMMAND_CALLBACK(input)
gui_input_move_previous_word (buffer);
else if (string_strcmp (argv[1], "move_next_word") == 0)
gui_input_move_next_word (buffer);
else if (string_strcmp (argv[1], "move_previous_line") == 0)
gui_input_move_previous_line (buffer);
else if (string_strcmp (argv[1], "move_next_line") == 0)
gui_input_move_next_line (buffer);
else if (string_strcmp (argv[1], "history_previous") == 0)
gui_input_history_local_previous (buffer);
else if (string_strcmp (argv[1], "history_next") == 0)
@@ -8352,18 +8366,26 @@ command_init ()
" delete_next_word: delete next word\n"
" delete_beginning_of_line: delete from beginning of line until "
"cursor\n"
" delete_beginning_of_input: delete from beginning of input until "
" delete_end_of_line: delete from cursor until end of line\n"
"cursor\n"
" delete_end_of_input: delete from cursor until end of input\n"
" delete_line: delete entire line\n"
" delete_input: delete entire input\n"
" clipboard_paste: paste from the internal clipboard\n"
" transpose_chars: transpose two chars\n"
" undo: undo last command line action\n"
" redo: redo last command line action\n"
" move_beginning_of_line: move cursor to beginning of line\n"
" move_beginning_of_input: move cursor to beginning of input\n"
" move_end_of_line: move cursor to end of line\n"
" move_end_of_input: move cursor to end of input\n"
" move_previous_char: move cursor to previous char\n"
" move_next_char: move cursor to next char\n"
" move_previous_word: move cursor to previous word\n"
" move_next_word: move cursor to next word\n"
" move_previous_line: move cursor to previous line\n"
" move_next_line: move cursor to next line\n"
" history_previous: recall previous command in current buffer "
"history\n"
" history_next: recall next command in current buffer history\n"
@@ -8387,12 +8409,16 @@ command_init ()
"search_stop_here || search_stop || "
"delete_previous_char || delete_next_char || delete_previous_word || "
"delete_previous_word_whitespace || delete_next_word || "
"delete_beginning_of_line || delete_end_of_line || delete_line || "
"delete_beginning_of_line || delete_beginning_of_input || "
"delete_end_of_line || delete_end_of_input || "
"delete_line || delete_input || "
"clipboard_paste || "
"transpose_chars || "
"undo || redo || "
"move_beginning_of_line || move_end_of_line || move_previous_char || "
"move_next_char || move_previous_word || move_next_word || "
"move_beginning_of_line || move_beginning_of_input || "
"move_end_of_line || move_end_of_input || "
"move_previous_char || move_next_char || move_previous_word || "
"move_next_word || move_previous_line || move_next_line || "
"history_previous || history_next || history_global_previous || "
"history_global_next || "
"grab_key || grab_raw_key || grab_raw_key_command || grab_key_command || "
+42
View File
@@ -270,6 +270,48 @@ utf8_next_char (const char *string)
return string + 1;
}
/*
* Gets pointer to the beginning of the UTF-8 line in a string.
*
* Returns pointer to the beginning of the UTF-8 line, NULL if string was NULL.
*/
const char *
utf8_beginning_of_line (const char *string_start, const char *string)
{
if (string && string[0] == '\n')
string = (char *)utf8_prev_char (string_start, string);
while (string && string[0] != '\n')
{
string = (char *)utf8_prev_char (string_start, string);
}
if (string)
return (char *)utf8_next_char (string);
return string_start;
}
/*
* Gets pointer to the end of the UTF-8 line in a string.
*
* Returns pointer to the end of the UTF-8 line, NULL if string was NULL.
*/
const char *
utf8_end_of_line (const char *string)
{
if (!string)
return NULL;
while (string[0] && string[0] != '\n')
{
string = (char *)utf8_next_char (string);
}
return string;
}
/*
* Gets UTF-8 char as an integer.
*
+3
View File
@@ -35,6 +35,9 @@ extern void utf8_normalize (char *string, char replacement);
extern const char *utf8_prev_char (const char *string_start,
const char *string);
extern const char *utf8_next_char (const char *string);
extern const char *utf8_beginning_of_line (const char *string_start,
const char *string);
extern const char *utf8_end_of_line (const char *string);
extern int utf8_char_int (const char *string);
extern int utf8_int_string (unsigned int unicode_value, char *string);
extern int utf8_char_size (const char *string);
+8 -1
View File
@@ -95,14 +95,19 @@ gui_key_default_bindings (int context, int create_option)
BIND("meta-x", "/buffer zoom");
BIND("meta-d", "/input delete_next_word");
BIND("ctrl-k", "/input delete_end_of_line");
BIND("meta-r", "/input delete_line");
BIND("meta-ctrl-k", "/input delete_end_of_input");
BIND("meta-r", "/input delete_input");
BIND("meta-R", "/input delete_line");
BIND("ctrl-t", "/input transpose_chars");
BIND("ctrl-u", "/input delete_beginning_of_line");
BIND("meta-ctrl-u", "/input delete_beginning_of_input");
BIND("ctrl-y", "/input clipboard_paste");
BIND("home", "/input move_beginning_of_line");
BIND("ctrl-a", "/input move_beginning_of_line");
BIND("shift-home", "/input move_beginning_of_input");
BIND("end", "/input move_end_of_line");
BIND("ctrl-e", "/input move_end_of_line");
BIND("shift-end", "/input move_end_of_input");
BIND("left", "/input move_previous_char");
BIND("ctrl-b", "/input move_previous_char");
BIND("right", "/input move_next_char");
@@ -115,6 +120,8 @@ gui_key_default_bindings (int context, int create_option)
BIND("down", "/input history_next");
BIND("ctrl-up", "/input history_global_previous");
BIND("ctrl-down", "/input history_global_next");
BIND("shift-up", "/input move_previous_line");
BIND("shift-down", "/input move_next_line");
BIND("meta-a", "/buffer jump smart");
BIND("meta-j,meta-f", "/buffer -");
BIND("meta-j,meta-l", "/buffer +");
+287 -7
View File
@@ -915,10 +915,104 @@ gui_input_delete_next_word (struct t_gui_buffer *buffer)
/*
* Deletes all from cursor pos to beginning of line (default key: ctrl-u).
*
* If cursor is at beginning of line, deletes to beginning of previous line.
*/
void
gui_input_delete_beginning_of_line (struct t_gui_buffer *buffer)
{
int length_deleted, size_deleted;
char *start, *beginning_of_line;
if (!buffer->input || (buffer->input_buffer_pos <= 0))
return;
gui_buffer_undo_snap (buffer);
start = (char *)utf8_add_offset (buffer->input_buffer,
buffer->input_buffer_pos);
beginning_of_line = (char *)utf8_beginning_of_line (buffer->input_buffer, start);
if (beginning_of_line == start)
{
beginning_of_line = (char *)utf8_prev_char (buffer->input_buffer,
beginning_of_line);
beginning_of_line = (char *)utf8_beginning_of_line (buffer->input_buffer,
beginning_of_line);
}
size_deleted = start - beginning_of_line;
length_deleted = utf8_strnlen (beginning_of_line, size_deleted);
gui_input_clipboard_copy (beginning_of_line, size_deleted);
memmove (beginning_of_line, start, strlen (start));
if (gui_input_optimize_size (
buffer,
buffer->input_buffer_size - size_deleted,
buffer->input_buffer_length - length_deleted))
{
buffer->input_buffer[buffer->input_buffer_size] = '\0';
buffer->input_buffer_pos = utf8_pos (buffer->input_buffer,
beginning_of_line - buffer->input_buffer);
}
gui_input_text_changed_modifier_and_signal (buffer,
1, /* save undo */
1); /* stop completion */
}
/*
* Deletes all from cursor pos to end of line (default key: ctrl-k).
*
* If cursor is at end of line, deletes to end of next line.
*/
void
gui_input_delete_end_of_line (struct t_gui_buffer *buffer)
{
int length_deleted, size_deleted;
char *start, *end_of_line;
if (!buffer->input)
return;
gui_buffer_undo_snap (buffer);
start = (char *)utf8_add_offset (buffer->input_buffer,
buffer->input_buffer_pos);
if (start[0] && start[0] == '\n')
end_of_line = (char *)utf8_next_char (start);
else
end_of_line = start;
end_of_line = (char *)utf8_end_of_line (end_of_line);
size_deleted = end_of_line - start;
length_deleted = utf8_strnlen (start, size_deleted);
gui_input_clipboard_copy (start, size_deleted);
memmove (start, end_of_line, strlen (end_of_line));
if (gui_input_optimize_size (
buffer,
buffer->input_buffer_size - size_deleted,
buffer->input_buffer_length - length_deleted))
{
buffer->input_buffer[buffer->input_buffer_size] = '\0';
buffer->input_buffer_pos = utf8_pos (buffer->input_buffer,
start - buffer->input_buffer);
}
gui_input_text_changed_modifier_and_signal (buffer,
1, /* save undo */
1); /* stop completion */
}
/*
* Deletes all from cursor pos to beginning of input (default key: alt-ctrl-u).
*/
void
gui_input_delete_beginning_of_input (struct t_gui_buffer *buffer)
{
int length_deleted, size_deleted;
char *start;
@@ -950,11 +1044,11 @@ gui_input_delete_beginning_of_line (struct t_gui_buffer *buffer)
}
/*
* Deletes all from cursor pos to end of line (default key: ctrl-k).
* Deletes all from cursor pos to end of input (default key: alt-ctrl-k).
*/
void
gui_input_delete_end_of_line (struct t_gui_buffer *buffer)
gui_input_delete_end_of_input (struct t_gui_buffer *buffer)
{
char *start;
int size_deleted;
@@ -977,11 +1071,51 @@ gui_input_delete_end_of_line (struct t_gui_buffer *buffer)
}
/*
* Deletes entire line (default key: alt-r).
* Deletes entire line (default key: alt-R).
*/
void
gui_input_delete_line (struct t_gui_buffer *buffer)
{
int length_deleted, size_deleted;
char *start, *beginning_of_line, *end_of_line;
if (!buffer->input)
return;
gui_buffer_undo_snap (buffer);
start = (char *)utf8_add_offset (buffer->input_buffer,
buffer->input_buffer_pos);
beginning_of_line = (char *)utf8_beginning_of_line (buffer->input_buffer, start);
end_of_line = (char *)utf8_end_of_line (start);
size_deleted = end_of_line - beginning_of_line;
length_deleted = utf8_strnlen (start, size_deleted);
memmove (beginning_of_line, end_of_line, strlen (end_of_line));
if (gui_input_optimize_size (
buffer,
buffer->input_buffer_size - size_deleted,
buffer->input_buffer_length - length_deleted))
{
buffer->input_buffer[buffer->input_buffer_size] = '\0';
buffer->input_buffer_pos = utf8_pos (buffer->input_buffer,
beginning_of_line - buffer->input_buffer);
}
gui_input_text_changed_modifier_and_signal (buffer,
1, /* save undo */
1); /* stop completion */
}
/*
* Deletes entire input (default key: alt-r).
*/
void
gui_input_delete_input (struct t_gui_buffer *buffer)
{
if (!buffer->input)
return;
@@ -1037,11 +1171,11 @@ gui_input_transpose_chars (struct t_gui_buffer *buffer)
}
/*
* Moves cursor to beginning of line (default key: home).
* Moves cursor to beginning of input (default key: shift-home).
*/
void
gui_input_move_beginning_of_line (struct t_gui_buffer *buffer)
gui_input_move_beginning_of_input (struct t_gui_buffer *buffer)
{
if (!buffer->input || (buffer->input_buffer_pos <= 0))
return;
@@ -1051,11 +1185,11 @@ gui_input_move_beginning_of_line (struct t_gui_buffer *buffer)
}
/*
* Moves cursor to end of line (default key: end).
* Moves cursor to end of input (default key: shift-end).
*/
void
gui_input_move_end_of_line (struct t_gui_buffer *buffer)
gui_input_move_end_of_input (struct t_gui_buffer *buffer)
{
if (!buffer->input
|| (buffer->input_buffer_pos >= buffer->input_buffer_length))
@@ -1067,6 +1201,73 @@ gui_input_move_end_of_line (struct t_gui_buffer *buffer)
gui_input_text_cursor_moved_signal (buffer);
}
/*
* Moves cursor to beginning of line (default key: home).
*
* If cursor is at beginning of line, moves to beginning of previous line.
*/
void
gui_input_move_beginning_of_line (struct t_gui_buffer *buffer)
{
char *pos, *original_pos;
if (!buffer->input || (buffer->input_buffer_pos <= 0))
return;
pos = (char *)utf8_add_offset (buffer->input_buffer,
buffer->input_buffer_pos);
original_pos = pos;
pos = (char *)utf8_beginning_of_line (buffer->input_buffer, pos);
if (pos == original_pos)
{
pos = (char *)utf8_prev_char (buffer->input_buffer, pos);
pos = (char *)utf8_beginning_of_line (buffer->input_buffer, pos);
}
buffer->input_buffer_pos = utf8_pos (buffer->input_buffer,
pos - buffer->input_buffer);
gui_input_text_cursor_moved_signal (buffer);
}
/*
* Moves cursor to end of line (default key: end).
*
* If cursor is at end of line, moves to end of next line.
*/
void
gui_input_move_end_of_line (struct t_gui_buffer *buffer)
{
char *pos;
if (!buffer->input
|| (buffer->input_buffer_pos >= buffer->input_buffer_length))
{
return;
}
pos = (char *)utf8_add_offset (buffer->input_buffer,
buffer->input_buffer_pos);
if (pos[0] && pos[0] == '\n')
{
pos = (char *)utf8_next_char (pos);
}
pos = (char *)utf8_end_of_line (pos);
if (pos[0])
{
buffer->input_buffer_pos =
utf8_pos (buffer->input_buffer,
pos - buffer->input_buffer);
}
else
buffer->input_buffer_pos = buffer->input_buffer_length;
gui_input_text_cursor_moved_signal (buffer);
}
/*
* Moves cursor to previous char (default key: left).
*/
@@ -1179,6 +1380,85 @@ gui_input_move_next_word (struct t_gui_buffer *buffer)
gui_input_text_cursor_moved_signal (buffer);
}
/*
* Moves cursor to previous line (default key: shift-up).
*/
void
gui_input_move_previous_line (struct t_gui_buffer *buffer)
{
int beginning_of_line_pos, length_from_beginning, i;
char *pos;
if (!buffer->input || (buffer->input_buffer_pos <= 0))
return;
pos = (char *)utf8_add_offset (buffer->input_buffer,
buffer->input_buffer_pos);
pos = (char *)utf8_beginning_of_line (buffer->input_buffer, pos);
if (pos != buffer->input_buffer)
{
beginning_of_line_pos = utf8_pos (buffer->input_buffer,
pos - buffer->input_buffer);
length_from_beginning = buffer->input_buffer_pos - beginning_of_line_pos;
pos = (char *)utf8_prev_char (buffer->input_buffer, pos);
pos = (char *)utf8_beginning_of_line (buffer->input_buffer, pos);
for (i = 0; pos[0] && pos[0] != '\n' && i < length_from_beginning; i++)
{
pos = (char *)utf8_next_char (pos);
}
buffer->input_buffer_pos = utf8_pos (buffer->input_buffer,
pos - buffer->input_buffer);
gui_input_text_cursor_moved_signal (buffer);
}
}
/*
* Moves cursor to next line (default key: shift-down).
*/
void
gui_input_move_next_line (struct t_gui_buffer *buffer)
{
int beginning_of_line_pos, length_from_beginning, i;
char *pos;
if (!buffer->input
|| (buffer->input_buffer_pos >= buffer->input_buffer_length))
{
return;
}
pos = (char *)utf8_add_offset (buffer->input_buffer,
buffer->input_buffer_pos);
pos = (char *)utf8_beginning_of_line (buffer->input_buffer, pos);
beginning_of_line_pos = utf8_pos (buffer->input_buffer,
pos - buffer->input_buffer);
length_from_beginning = buffer->input_buffer_pos - beginning_of_line_pos;
pos = (char *)utf8_end_of_line (pos);
if (pos[0])
{
pos = (char *)utf8_next_char (pos);
for (i = 0; pos[0] && pos[0] != '\n' && i < length_from_beginning; i++)
{
pos = (char *)utf8_next_char (pos);
}
buffer->input_buffer_pos = utf8_pos (buffer->input_buffer,
pos - buffer->input_buffer);
gui_input_text_cursor_moved_signal (buffer);
}
}
/*
* Recalls previous command from local or global history.
*/
+7
View File
@@ -58,14 +58,21 @@ extern void gui_input_delete_previous_word_whitespace (struct t_gui_buffer *buff
extern void gui_input_delete_next_word (struct t_gui_buffer *buffer);
extern void gui_input_delete_beginning_of_line (struct t_gui_buffer *buffer);
extern void gui_input_delete_end_of_line (struct t_gui_buffer *buffer);
extern void gui_input_delete_beginning_of_input (struct t_gui_buffer *buffer);
extern void gui_input_delete_end_of_input (struct t_gui_buffer *buffer);
extern void gui_input_delete_line (struct t_gui_buffer *buffer);
extern void gui_input_delete_input (struct t_gui_buffer *buffer);
extern void gui_input_transpose_chars (struct t_gui_buffer *buffer);
extern void gui_input_move_beginning_of_input (struct t_gui_buffer *buffer);
extern void gui_input_move_end_of_input (struct t_gui_buffer *buffer);
extern void gui_input_move_beginning_of_line (struct t_gui_buffer *buffer);
extern void gui_input_move_end_of_line (struct t_gui_buffer *buffer);
extern void gui_input_move_previous_char (struct t_gui_buffer *buffer);
extern void gui_input_move_next_char (struct t_gui_buffer *buffer);
extern void gui_input_move_previous_word (struct t_gui_buffer *buffer);
extern void gui_input_move_next_word (struct t_gui_buffer *buffer);
extern void gui_input_move_previous_line (struct t_gui_buffer *buffer);
extern void gui_input_move_next_line (struct t_gui_buffer *buffer);
extern void gui_input_history_local_previous (struct t_gui_buffer *buffer);
extern void gui_input_history_local_next (struct t_gui_buffer *buffer);
extern void gui_input_history_global_previous (struct t_gui_buffer *buffer);
+31 -5
View File
@@ -114,11 +114,12 @@ extern "C"
#define UTF8_4BYTES_TRUNCATED_3 "\xf0\xa4\xad"
/* "noël" */
#define UTF8_NOEL_VALID "no\xc3\xabl"
#define UTF8_NOEL_INVALID "no\xc3l"
#define UTF8_NOEL_INVALID2 "no\xff\xffl"
#define UTF8_NOEL_INVALID_NORM "no?l"
#define UTF8_NOEL_INVALID2_NORM "no??l"
#define UTF8_NOEL_VALID "no\xc3\xabl"
#define UTF8_NOEL_VALID_MULTILINE "no\xc3\xabl\nno\xc3\xabl"
#define UTF8_NOEL_INVALID "no\xc3l"
#define UTF8_NOEL_INVALID2 "no\xff\xffl"
#define UTF8_NOEL_INVALID_NORM "no?l"
#define UTF8_NOEL_INVALID2_NORM "no??l"
TEST_GROUP(CoreUtf8)
{
@@ -323,6 +324,8 @@ TEST(CoreUtf8, Normalize)
* Tests functions:
* utf8_prev_char
* utf8_next_char
* utf8_beginning_of_line
* utf8_end_of_line
* utf8_add_offset
* utf8_real_pos
* utf8_pos
@@ -333,6 +336,7 @@ TEST(CoreUtf8, Move)
const char *ptr;
const char *empty_string = "";
const char *noel_valid = UTF8_NOEL_VALID;
const char *noel_valid_multiline = UTF8_NOEL_VALID_MULTILINE;
const char *utf8_2bytes_truncated_1 = UTF8_2BYTES_TRUNCATED_1;
const char *utf8_3bytes_truncated_1 = UTF8_3BYTES_TRUNCATED_1;
const char *utf8_3bytes_truncated_2 = UTF8_3BYTES_TRUNCATED_2;
@@ -377,6 +381,28 @@ TEST(CoreUtf8, Move)
POINTERS_EQUAL(utf8_4bytes_truncated_3 + 3,
utf8_next_char (utf8_4bytes_truncated_3));
/* beginning/end of line */
POINTERS_EQUAL(NULL, utf8_beginning_of_line (NULL, NULL));
POINTERS_EQUAL(NULL, utf8_end_of_line (NULL));
ptr = utf8_end_of_line (noel_valid_multiline);
STRCMP_EQUAL("\nnoël", ptr);
ptr = utf8_end_of_line (ptr);
STRCMP_EQUAL("\nnoël", ptr);
ptr = utf8_next_char (ptr);
ptr = utf8_end_of_line (ptr);
STRCMP_EQUAL("", ptr);
ptr = utf8_end_of_line (ptr);
STRCMP_EQUAL("", ptr);
ptr = utf8_beginning_of_line (noel_valid_multiline, ptr);
STRCMP_EQUAL(noel_valid, ptr);
ptr = utf8_beginning_of_line (noel_valid_multiline, ptr);
STRCMP_EQUAL(noel_valid, ptr);
ptr = utf8_prev_char (noel_valid_multiline, ptr);
ptr = utf8_beginning_of_line (noel_valid_multiline, ptr);
STRCMP_EQUAL(noel_valid_multiline, ptr);
ptr = utf8_beginning_of_line (noel_valid_multiline, ptr);
STRCMP_EQUAL(noel_valid_multiline, ptr);
/* add offset */
POINTERS_EQUAL(NULL, utf8_add_offset (NULL, 0));
ptr = utf8_add_offset (noel_valid, 0);