linux-qubasis

linux oasis port as a qubes template

git clone https://9o.is/git/linux-qubasis.git

commit 39c59ae129f4b98b1335ce65a0a264cf98ad7959
parent 4f6cc1e97328ffd2cc1c950d05c6ba03103d831c
Author: Jul <jul@9o.is>
Date:   Thu, 31 Jul 2025 03:35:05 -0400

add fzy multi-selection support

Diffstat:
Mpkg/fzy/patches/0001-add-carriage-return-to-tty_clearline.patch | 2+-
Mpkg/fzy/patches/0002-Reduce-screen-and-cursor-flickering.patch | 2+-
Apkg/fzy/patches/0003-add-multi-selection.patch | 316+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 318 insertions(+), 2 deletions(-)

diff --git a/pkg/fzy/patches/0001-add-carriage-return-to-tty_clearline.patch b/pkg/fzy/patches/0001-add-carriage-return-to-tty_clearline.patch @@ -1,7 +1,7 @@ From a7f705a08f5a10b0cdb76ffddd1dee0e3d06ea48 Mon Sep 17 00:00:00 2001 From: Jul <jul@qh.is> Date: Thu, 31 Jul 2025 00:13:39 -0400 -Subject: [PATCH 1/2] add carriage return to tty_clearline +Subject: [PATCH 1/3] add carriage return to tty_clearline --- src/tty.c | 2 +- diff --git a/pkg/fzy/patches/0002-Reduce-screen-and-cursor-flickering.patch b/pkg/fzy/patches/0002-Reduce-screen-and-cursor-flickering.patch @@ -1,7 +1,7 @@ From 03c3ef3fd9e0638331453db4bbdec091f61c1572 Mon Sep 17 00:00:00 2001 From: leo-arch <leonardoabramovich2@gmail.com> Date: Fri, 18 Jul 2025 21:39:07 -0300 -Subject: [PATCH 2/2] Reduce screen and cursor flickering +Subject: [PATCH 2/3] Reduce screen and cursor flickering --- src/tty.c | 8 ++++++++ diff --git a/pkg/fzy/patches/0003-add-multi-selection.patch b/pkg/fzy/patches/0003-add-multi-selection.patch @@ -0,0 +1,316 @@ +From 1dc1c60924da9ab2d8af80cf89b59b65a2e81ff8 Mon Sep 17 00:00:00 2001 +From: Jul <jul@qh.is> +Date: Thu, 31 Jul 2025 03:34:16 -0400 +Subject: [PATCH 3/3] add multi-selection + +--- + src/options.c | 8 ++- + src/options.h | 1 + + src/tty_interface.c | 165 ++++++++++++++++++++++++++++++++++++++++++-- + 3 files changed, 167 insertions(+), 7 deletions(-) + +diff --git a/src/options.c b/src/options.c +index 485fc98..3117ca6 100644 +--- a/src/options.c ++++ b/src/options.c +@@ -12,6 +12,7 @@ static const char *usage_str = + "" + "Usage: fzy [OPTION]...\n" + " -l, --lines=LINES Specify how many lines of results to show (default 10)\n" ++ " -m, --multi Enable multi-selection\n" + " -p, --prompt=PROMPT Input prompt (default '> ')\n" + " -q, --query=QUERY Use QUERY as the initial search string\n" + " -e, --show-matches=QUERY Output the sorted matches of QUERY\n" +@@ -39,6 +40,7 @@ static struct option longopts[] = {{"show-matches", required_argument, NULL, 'e' + {"workers", required_argument, NULL, 'j'}, + {"show-info", no_argument, NULL, 'i'}, + {"help", no_argument, NULL, 'h'}, ++ {"multi", no_argument, NULL, 'm'}, + {NULL, 0, NULL, 0}}; + + void options_init(options_t *options) { +@@ -54,13 +56,14 @@ void options_init(options_t *options) { + options->workers = DEFAULT_WORKERS; + options->input_delimiter = '\n'; + options->show_info = DEFAULT_SHOW_INFO; ++ options->multi = 0; + } + + void options_parse(options_t *options, int argc, char *argv[]) { + options_init(options); + + int c; +- while ((c = getopt_long(argc, argv, "vhs0e:q:l:t:p:j:i", longopts, NULL)) != -1) { ++ while ((c = getopt_long(argc, argv, "mvhs0e:q:l:t:p:j:i", longopts, NULL)) != -1) { + switch (c) { + case 'v': + printf("%s " VERSION " © 2014-2025 John Hawthorn\n", argv[0]); +@@ -68,6 +71,9 @@ void options_parse(options_t *options, int argc, char *argv[]) { + case 's': + options->show_scores = 1; + break; ++ case 'm': ++ options->multi = 1; ++ break; + case '0': + options->input_delimiter = '\0'; + break; +diff --git a/src/options.h b/src/options.h +index 1a0886e..49185ba 100644 +--- a/src/options.h ++++ b/src/options.h +@@ -17,6 +17,7 @@ typedef struct { + unsigned int workers; + char input_delimiter; + int show_info; ++ int multi; + } options_t; + + void options_init(options_t *options); +diff --git a/src/tty_interface.c b/src/tty_interface.c +index 6828be8..a0392bd 100644 +--- a/src/tty_interface.c ++++ b/src/tty_interface.c +@@ -7,6 +7,126 @@ + #include "tty_interface.h" + #include "../config.h" + ++/* An array numbers to store the index of selected entries (choices) */ ++static size_t *selection_marks = (size_t *)NULL; ++ ++/* ++ * Create a size_t array big enough to hold all availalable choices, ++ * and initialize it to zero ++ */ ++static void ++init_selection_marks(tty_interface_t *state) ++{ ++ if (state->options->multi == 0) { ++ return; ++ } ++ ++ selection_marks = (size_t *)malloc(state->choices->available * sizeof(size_t)); ++ for (size_t i = 0; i < state->choices->available; i++) { ++ selection_marks[i] = 0; ++ } ++} ++ ++/* Return the amount of selected entries in the list of matches */ ++static size_t ++count_selections(tty_interface_t *state) ++{ ++ size_t c = 0; ++ for (size_t i = 0; i < state->choices->available; i++) { ++ if (selection_marks[i] == 1) { ++ c++; ++ } ++ } ++ ++ return c; ++} ++ ++/* ++ * Store current selected entries into an array to print each of them ++ * at exit. Return this array of strings if success and NULL in case ++ * of error or no selected entries ++ */ ++static char ** ++save_selections(tty_interface_t *state) ++{ ++ size_t i, c = 0; ++ size_t n = count_selections(state); ++ if (n == 0) { ++ return (char **)NULL; ++ } ++ ++ char **s = (char **)malloc((n + 2) * sizeof(char *)); ++ ++ for (i = 0; i < state->choices->available; i++) { ++ if (selection_marks[i] != 1) { ++ continue; ++ } ++ ++ const char *name = choices_get(state->choices, i); ++ if (!name) { ++ continue; ++ } ++ ++ s[c] = (char *)malloc((strlen(name) + 1) * sizeof(char)); ++ strcpy(s[c], name); ++ c++; ++ ++ if (c == n) { ++ break; ++ } ++ } ++ ++ if (c == 0) { ++ free(s); ++ return (char **)NULL; ++ } ++ ++ s[c] = (char *)NULL; ++ return s; ++} ++ ++/* Free the array of selected entries generated by save_selections() */ ++static void ++free_selections(char **s) ++{ ++ size_t i; ++ for (i = 0; s[i]; i++) { ++ free(s[i]); ++ } ++ free(s); ++} ++ ++/* Print the list of selected entries generated by save_selections() */ ++static void ++print_selections(char **s) ++{ ++ size_t i; ++ for (i = 0; s[i]; i++) { ++ printf("%s\n", s[i]); ++ } ++} ++ ++/* Free the size_t array generated by init_selection_marks() */ ++static void ++free_selection_marks(tty_interface_t *state) ++{ ++ if (state->options->multi == 1) { ++ free(selection_marks); ++ selection_marks = (size_t *)NULL; ++ } ++} ++ ++/* ++ * Set to 1 the index of the current/selected entry in the selection_marks ++ * array. If this entry is already marked/selected, set it to zero ++ */ ++static void ++action_select(tty_interface_t *state) ++{ ++ size_t s = selection_marks[state->choices->selection]; ++ selection_marks[state->choices->selection] = s == 1 ? 0 : 1; ++} ++ + static int isprint_unicode(char c) { + return isprint(c) || c & (1 << 7); + } +@@ -18,7 +138,7 @@ static int is_boundary(char c) { + static void clear(tty_interface_t *state) { + tty_t *tty = state->tty; + +- tty_setcol(tty, 0); ++ tty_setcol(tty, state->options->multi ? 2 : 0); + size_t line = 0; + while (line++ < state->options->num_lines + (state->options->show_info ? 1 : 0)) { + tty_newline(tty); +@@ -92,11 +212,14 @@ static void draw(tty_interface_t *state) { + } + + tty_hide_cursor(tty); +- tty_setcol(tty, 0); ++ tty_setcol(tty, options->multi ? 2 : 0); + tty_printf(tty, "%s%s", options->prompt, state->search); + tty_clearline(tty); + +- if (options->show_info) { ++ if (options->show_info && options->multi) { ++ tty_printf(tty, "\n[%lu/%lu/%lu]", count_selections(state), choices->available, choices->size); ++ tty_clearline(tty); ++ } else if (options->show_info) { + tty_printf(tty, "\n[%lu/%lu]", choices->available, choices->size); + tty_clearline(tty); + } +@@ -106,6 +229,11 @@ static void draw(tty_interface_t *state) { + tty_clearline(tty); + const char *choice = choices_get(choices, i); + if (choice) { ++ if (options->multi == 1 && selection_marks[i] == 1) { ++ tty_printf(tty, "%*c %s", 1, '*', ""); ++ } else { ++ tty_printf(tty, "%*s", 2, ""); ++ } + draw_match(state, choice, i == choices->selection); + } + } +@@ -113,7 +241,7 @@ static void draw(tty_interface_t *state) { + if (num_lines + options->show_info) + tty_moveup(tty, num_lines + options->show_info); + +- tty_setcol(tty, 0); ++ tty_setcol(tty, options->multi ? 2 : 0); + fputs(options->prompt, tty->fout); + for (size_t i = 0; i < state->cursor; i++) + fputc(state->search[i], tty->fout); +@@ -137,6 +265,22 @@ static void update_state(tty_interface_t *state) { + static void action_emit(tty_interface_t *state) { + update_state(state); + ++ if (state->options->multi == 1) { ++ char **s = save_selections(state); ++ free_selection_marks(state); ++ ++ if (s) { ++ clear(state); ++ tty_close(state->tty); ++ ++ print_selections(s); ++ free_selections(s); ++ ++ state->exit = EXIT_SUCCESS; ++ return; ++ } ++ } ++ + /* Reset the tty as close as possible to the previous state */ + clear(state); + +@@ -239,6 +383,10 @@ static void action_pagedown(tty_interface_t *state) { + } + + static void action_autocomplete(tty_interface_t *state) { ++ if (state->options->multi == 1) { ++ action_select(state); ++ return; ++ } + update_state(state); + const char *current_selection = choices_get(state->choices, state->choices->selection); + if (current_selection) { +@@ -377,6 +525,7 @@ static void handle_input(tty_interface_t *state, const char *s, int handle_ambig + } + + int tty_interface_run(tty_interface_t *state) { ++ init_selection_marks(state); + draw(state); + + for (;;) { +@@ -392,8 +541,10 @@ int tty_interface_run(tty_interface_t *state) { + if (state->ambiguous_key_pending == 1) + continue; + +- if (state->exit >= 0) ++ if (state->exit >= 0) { ++ free_selection_marks(state); + return state->exit; ++ } + + draw(state); + } while (tty_input_ready(state->tty, state->ambiguous_key_pending ? KEYTIMEOUT : 0, 0)); +@@ -402,8 +553,10 @@ int tty_interface_run(tty_interface_t *state) { + char s[1] = ""; + handle_input(state, s, 1); + +- if (state->exit >= 0) ++ if (state->exit >= 0) { ++ free_selection_marks(state); + return state->exit; ++ } + } + + update_state(state); +-- +2.50.1 +