Skip to content

Commit fde75d1

Browse files
committed
slash: keep track of changed bytes in buffer for refresh
Change the boolean refresh_buffer to a half-open interval of bytes needing screen refresh. This allows both another optimization and simplification of the refresh code. Signed-off-by: Jeppe Ledet-Pedersen <jlp@satlab.com>
1 parent 6a6d23e commit fde75d1

2 files changed

Lines changed: 111 additions & 61 deletions

File tree

include/slash/slash.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -272,8 +272,9 @@ struct slash_command {
272272
* @cursor_screen: Current index of cursor in line buffer on screen.
273273
* @length: Current amount of used bytes in line buffer.
274274
* @length_screen: Current amount of used bytes in line buffer on screen.
275+
* @change_start: Index of first byte in line buffer that needs screen refresh.
276+
* @change_end: Index of first byte in line buffer that does not need screen refresh.
275277
* @refresh_full: Force a full screen refresh including prompt.
276-
* @refresh_buffer: Force a screen refresh of buffer.
277278
* @last_char: Last input character.
278279
* @history_size: Size in byte of the history buffer.
279280
* @history_depth: Number of history entries browsed back.
@@ -314,8 +315,9 @@ struct slash {
314315
size_t cursor_screen;
315316
size_t length;
316317
size_t length_screen;
318+
size_t change_start;
319+
size_t change_end;
317320
bool refresh_full;
318-
bool refresh_buffer;
319321
char last_char;
320322

321323
/* History */

src/slash.c

Lines changed: 107 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,19 @@ static int slash_getchar(struct slash *slash)
198198
return c;
199199
}
200200

201+
static void slash_mark_changed(struct slash *slash, size_t start, size_t end)
202+
{
203+
if (slash->change_start == slash->change_end) {
204+
slash->change_start = start;
205+
slash->change_end = end;
206+
} else {
207+
if (start < slash->change_start)
208+
slash->change_start = start;
209+
if (end > slash->change_end)
210+
slash->change_end = end;
211+
}
212+
}
213+
201214
#ifdef SLASH_HAVE_SELECT
202215
static int slash_wait_select(struct slash *slash, unsigned int ms)
203216
{
@@ -622,7 +635,9 @@ static void slash_set_completion(struct slash *slash,
622635
complete[len] = '\0';
623636
if (space)
624637
strncat(complete, " ", slash->line_size - 1);
625-
slash->cursor = slash->length = strlen(slash->buffer);
638+
slash->length = strlen(slash->buffer);
639+
slash_mark_changed(slash, slash->cursor, slash->length);
640+
slash->cursor = slash->length;
626641
}
627642

628643
static bool slash_complete_matches(struct slash *slash,
@@ -875,7 +890,7 @@ static bool slash_history_next(struct slash *slash)
875890
slash->buffer[srclen] = '\0';
876891
slash->history_cursor = src;
877892
slash->cursor = slash->length = srclen;
878-
slash->refresh_buffer = true;
893+
slash_mark_changed(slash, 0, slash->length);
879894

880895
/* Rewind if use to store buffer temporarily */
881896
if (!slash->history_depth && slash->history_cursor != slash->history_tail)
@@ -905,28 +920,64 @@ static bool slash_history_previous(struct slash *slash)
905920
slash->buffer[srclen] = '\0';
906921
slash->history_cursor = src;
907922
slash->cursor = slash->length = srclen;
908-
slash->refresh_buffer = true;
923+
slash_mark_changed(slash, 0, slash->length);
909924

910925
return true;
911926
}
912927

913928
/* Line editing */
914-
static int slash_cursor_back(struct slash *slash, size_t n)
929+
static int slash_screen_cursor_back(struct slash *slash, size_t n)
915930
{
916931
/* If we need to move more than 3 colums, CUB uses fewer bytes */
917932
if (n > 3) {
918933
slash_printf(slash, ESCAPE("%zuD"), n);
934+
slash->cursor_screen -= n;
919935
} else {
920-
while (n--)
936+
while (n--) {
921937
slash_putchar(slash, '\b');
938+
slash->cursor_screen--;
939+
}
940+
}
941+
942+
return 0;
943+
}
944+
945+
static int slash_screen_cursor_forward(struct slash *slash, size_t n)
946+
{
947+
/* If we need to move more than 3 colums, CUF uses fewer bytes */
948+
if (n > 3) {
949+
slash_printf(slash, ESCAPE("%zuC"), n);
950+
slash->cursor_screen += n;
951+
} else {
952+
while (n--) {
953+
slash_putchar(slash, slash->buffer[slash->cursor_screen]);
954+
slash->cursor_screen++;
955+
}
956+
}
957+
958+
return 0;
959+
}
960+
961+
static int slash_screen_cursor_to_column(struct slash *slash, size_t col)
962+
{
963+
size_t diff;
964+
965+
if (col > slash->cursor_screen) {
966+
diff = col - slash->cursor_screen;
967+
return slash_screen_cursor_forward(slash, diff);
968+
} else if (col < slash->cursor_screen) {
969+
diff = slash->cursor_screen - col;
970+
return slash_screen_cursor_back(slash, diff);
922971
}
923972

924973
return 0;
925974
}
975+
926976
int slash_refresh(struct slash *slash)
927977
{
928978
const char *esc = ESCAPE("K");
929979

980+
/* Full refresh with prompt */
930981
if (slash->refresh_full) {
931982
slash_putchar(slash, '\r');
932983
if (slash_write(slash, esc, strlen(esc)) < 0)
@@ -935,61 +986,64 @@ int slash_refresh(struct slash *slash)
935986
return -1;
936987
slash->cursor_screen = 0;
937988
slash->length_screen = 0;
989+
slash->change_start = 0;
990+
slash->change_end = slash->length;
938991
slash->refresh_full = false;
939992
}
940993

941-
if (slash->refresh_buffer) {
942-
slash_cursor_back(slash, slash->cursor_screen);
943-
slash->cursor_screen = 0;
944-
slash->refresh_buffer = false;
945-
}
946-
947-
while (slash->cursor_screen < slash->cursor) {
948-
slash_putchar(slash, slash->buffer[slash->cursor_screen]);
949-
slash->cursor_screen++;
950-
}
951-
952-
if (slash->cursor_screen > slash->cursor) {
953-
slash_cursor_back(slash,
954-
slash->cursor_screen - slash->cursor);
955-
slash->cursor_screen = slash->cursor;
956-
}
957-
958-
if (slash->length_screen != slash->length) {
994+
/* Buffer contents have changed */
995+
if (slash->change_start != slash->change_end) {
996+
if (slash_screen_cursor_to_column(slash, slash->change_start) < 0)
997+
return -1;
959998
if (slash_write(slash,
960-
&slash->buffer[slash->cursor],
961-
slash->length - slash->cursor) < 0)
999+
&slash->buffer[slash->change_start],
1000+
slash->change_end - slash->change_start) < 0)
9621001
return -1;
963-
slash->cursor_screen = slash->length;
964-
965-
if (slash->length_screen > slash->length) {
966-
if (slash_write(slash, esc, strlen(esc)) < 0)
967-
return -1;
968-
}
969-
970-
if (slash->cursor_screen > slash->cursor) {
971-
slash_cursor_back(slash,
972-
slash->cursor_screen - slash->cursor);
973-
slash->cursor_screen = slash->cursor;
974-
}
1002+
slash->cursor_screen = slash->change_end;
1003+
slash->change_start = slash->change_end = 0;
1004+
}
9751005

976-
slash->length_screen = slash->length;
1006+
/* If screen contents were truncated, erase remainder */
1007+
if (slash->length_screen > slash->length) {
1008+
if (slash_screen_cursor_to_column(slash, slash->length) < 0)
1009+
return -1;
1010+
if (slash_write(slash, esc, strlen(esc)) < 0)
1011+
return -1;
9771012
}
1013+
slash->length_screen = slash->length;
1014+
1015+
/* Restore screen cursor position */
1016+
if (slash_screen_cursor_to_column(slash, slash->cursor) < 0)
1017+
return -1;
9781018

9791019
return slash_write_flush(slash);
9801020
}
9811021

9821022
static void slash_insert(struct slash *slash, int c)
9831023
{
984-
if (slash->length + 1 > slash->line_size)
1024+
if (slash->length >= slash->line_size)
9851025
return;
9861026

9871027
memmove(&slash->buffer[slash->cursor + 1],
9881028
&slash->buffer[slash->cursor],
9891029
slash->length - slash->cursor);
9901030
slash->buffer[slash->cursor] = c;
991-
slash->cursor++;
9921031
slash->length++;
1032+
slash_mark_changed(slash, slash->cursor, slash->length);
1033+
slash->cursor++;
1034+
slash->buffer[slash->length] = '\0';
1035+
}
1036+
1037+
static void slash_delete(struct slash *slash)
1038+
{
1039+
if (slash->cursor >= slash->length)
1040+
return;
1041+
1042+
slash->length--;
1043+
memmove(&slash->buffer[slash->cursor],
1044+
&slash->buffer[slash->cursor + 1],
1045+
slash->length - slash->cursor);
1046+
slash_mark_changed(slash, slash->cursor, slash->length);
9931047
slash->buffer[slash->length] = '\0';
9941048
}
9951049

@@ -998,6 +1052,8 @@ void slash_reset(struct slash *slash)
9981052
slash->buffer[0] = '\0';
9991053
slash->length = 0;
10001054
slash->cursor = 0;
1055+
slash->change_start = 0;
1056+
slash->change_end = 0;
10011057
slash->refresh_full = true;
10021058
}
10031059

@@ -1025,17 +1081,6 @@ static void slash_arrow_left(struct slash *slash)
10251081
slash->cursor--;
10261082
}
10271083

1028-
static void slash_delete(struct slash *slash)
1029-
{
1030-
if (slash->cursor < slash->length) {
1031-
slash->length--;
1032-
memmove(&slash->buffer[slash->cursor],
1033-
&slash->buffer[slash->cursor + 1],
1034-
slash->length - slash->cursor);
1035-
slash->buffer[slash->length] = '\0';
1036-
}
1037-
}
1038-
10391084
void slash_clear_screen(struct slash *slash)
10401085
{
10411086
const char *esc = ESCAPE("H") ESCAPE("2J");
@@ -1045,14 +1090,16 @@ void slash_clear_screen(struct slash *slash)
10451090

10461091
static void slash_backspace(struct slash *slash)
10471092
{
1048-
if (slash->cursor > 0) {
1049-
slash->cursor--;
1050-
slash->length--;
1051-
memmove(&slash->buffer[slash->cursor],
1052-
&slash->buffer[slash->cursor + 1],
1053-
slash->length - slash->cursor);
1054-
slash->buffer[slash->length] = '\0';
1055-
}
1093+
if (slash->cursor == 0)
1094+
return;
1095+
1096+
slash->cursor--;
1097+
slash->length--;
1098+
memmove(&slash->buffer[slash->cursor],
1099+
&slash->buffer[slash->cursor + 1],
1100+
slash->length - slash->cursor);
1101+
slash_mark_changed(slash, slash->cursor, slash->length);
1102+
slash->buffer[slash->length] = '\0';
10561103
}
10571104

10581105
static void slash_delete_word(struct slash *slash)
@@ -1068,6 +1115,7 @@ static void slash_delete_word(struct slash *slash)
10681115
memmove(&slash->buffer[slash->cursor],
10691116
&slash->buffer[old_cursor],
10701117
slash->length - slash->cursor);
1118+
slash_mark_changed(slash, slash->cursor, slash->length);
10711119
slash->buffer[slash->length] = '\0';
10721120
}
10731121

0 commit comments

Comments
 (0)