summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorpgen <p.gen.progs@gmail.com>2016-03-11 20:45:06 +0100
committerpgen <p.gen.progs@gmail.com>2016-03-11 22:39:25 +0100
commit2e88be0fdd2cf5ee867237bb11a4483fd04dc53c (patch)
tree0a1eb82cbf072c7d51fad2061727482e6bb67a68
parent1c9c8154061c35a58939d01be92f182689d09ca9 (diff)
Fix the -s option and add a search by regular expression syntax
- syntax change: - use the -s/... syntax for regular expression search - use the -s#... syntax for absolute positioning - use the -s... syntax for prefix search - clarify the documentation - ensure that the words array is correctly updated after previous possible alterations
-rw-r--r--smenu.129
-rw-r--r--smenu.c163
2 files changed, 136 insertions, 56 deletions
diff --git a/smenu.1 b/smenu.1
index ad03c4d..3afc26f 100644
--- a/smenu.1
+++ b/smenu.1
@@ -243,22 +243,31 @@ Note that if this mode each column has the same width.
.IP "\fB-s\fP \fIpattern\fP"
Pre-Position the cursor to the first word matching the specified pattern.
-\fIpattern\fP" can be:
+\fIpattern\fP can be:
.RS
.IP * 2
-A \fBnumber\fP giving the initial position of the cursor (counting from
-0). If this number if greater than the number of words, the cursor will
-be set on la last position.
+A "\fB#\fP" immediately followed by a \fBnumber\fP giving the initial
+position of the cursor (counting from 0). If this number if greater than
+the number of words, the cursor will be set on the latest selectable
+position.
.IP * 2
-The string \fBlast\fP meaning that we want the initial position to be
-on the last word.
+A single "\fB#\fP" or the string \fB#last\fP to also set the initial
+cursor position at the latest selectable word position.
.IP * 2
A string starting with a "\fB/\fP" indicating that we want the cursor
-to be set on the first word matching the \fBprefix\fP string following
-the "\fB/\fP" (\fB/Ca\fP will match \fBCancel\fP by example).
+to be set at the position of the first word matching the given regular
+expression.
+.IP * 2
+A \fBprefix\fP string indicating that we want the cursor to be set on the
+first word matching the string given (\fBCa\fP will match \fBCancel\fP
+by example).
.PP
-Every failure will do nothing, resulting with the cursor set on the
-first word.
+Warning, when searching for a prefix or a regular expression, smenu
+only look for them only after an eventual modification, so per example,
+the command:
+\f(CBsmenu -I/c/x/ -s/c <<< "a b c d"\fP won't find c and put the cursor
+on \fBa\fP but \f(CBsmenu -I/c/x/v -s/c <<< "a b c d"\fP will find it and
+put the cursor on the \fBx\fP substituting the \fBc\fP on screen only
.RE
.IP "\fB-m\fP \fImessage\fP"
Displays a message above the window. Beware, it will truncated if it
diff --git a/smenu.c b/smenu.c
index ca1b3db..e9f043e 100644
--- a/smenu.c
+++ b/smenu.c
@@ -5512,6 +5512,8 @@ main(int argc, char *argv[])
word_a[count].special_level = special_level;
+ /* Save the non modified word in .orig if it has been altered */
+ /* """""""""""""""""""""""""""""""""""""""""""""""""""""""""" */
if (strcmp(word, dest) != 0)
word_a[count].orig = word;
else
@@ -5531,6 +5533,33 @@ main(int argc, char *argv[])
else
word_a[count].is_last = 0;
+ /* Store the new max number of bytes in a word */
+ /* """"""""""""""""""""""""""""""""""""""""""" */
+ if ((size = (int) word_len) > tab_real_max_size)
+ tab_real_max_size = (int) word_len;
+
+ /* Store the new max word width */
+ /* """""""""""""""""""""""""""" */
+ size = (int) mbstowcs(0, dest, 0);
+
+ if ((size = wcswidth((tmpw = mb_strtowcs(dest)), size)) > tab_max_size)
+ tab_max_size = size;
+
+ free(tmpw);
+
+ /* When the visual only flag is set, we keep the unaltered word so */
+ /* that it can be restituted even if its visual and searchable */
+ /* representation may have been altered by the previous code */
+ /* """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" */
+ if ((word_a[count].is_selectable & include_visual_only)
+ | ((!word_a[count].is_selectable) & exclude_visual_only))
+ {
+ free(word_a[count].orig);
+ word_a[count].orig = unaltered_word;
+ }
+ else
+ free(unaltered_word);
+
/* If the word is selectable insert it in the TST tree */
/* with its associated index in the input stream. */
/* """"""""""""""""""""""""""""""""""""""""""""""""""" */
@@ -5562,33 +5591,6 @@ main(int argc, char *argv[])
free(w);
}
- /* Store the new max number of bytes in a word */
- /* """"""""""""""""""""""""""""""""""""""""""" */
- if ((size = (int) word_len) > tab_real_max_size)
- tab_real_max_size = (int) word_len;
-
- /* Store the new max word width */
- /* """""""""""""""""""""""""""" */
- size = (int) mbstowcs(0, dest, 0);
-
- if ((size = wcswidth((tmpw = mb_strtowcs(dest)), size)) > tab_max_size)
- tab_max_size = size;
-
- free(tmpw);
-
- /* When the visual only flag is set, we keep the unaltered word so */
- /* that it can be restituted even if its visual and searchable */
- /* representation may have been altered by the previous code */
- /* """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" */
- if ((word_a[count].is_selectable & include_visual_only)
- | ((!word_a[count].is_selectable) & exclude_visual_only))
- {
- free(word_a[count].orig);
- word_a[count].orig = unaltered_word;
- }
- else
- free(unaltered_word);
-
/* One more word... */
/* """""""""""""""" */
if (count == limits.words)
@@ -5753,38 +5755,107 @@ main(int argc, char *argv[])
last_selectable--;
if (pre_selection_index == NULL)
+ /* option -s was not used */
+ /* """""""""""""""""""""" */
current = first_selectable;
- else if (strcmp(pre_selection_index, "last") == 0)
- current = last_selectable;
else if (*pre_selection_index == '/')
{
- wchar_t *w;
+ /* A regular expression is expected */
+ /* """""""""""""""""""""""""""""""" */
+ regex_t re;
+ int index;
- new_current = last_selectable;
- if (NULL != tst_prefix_search(tst,
- w = mb_strtowcs(pre_selection_index + 1),
- tst_cb_cli))
- current = new_current;
+ if (regcomp(&re, pre_selection_index + 1, REG_EXTENDED | REG_NOSUB) != 0)
+ {
+ fprintf(stderr, "Invalid regular expression (%s)\n", pre_selection_index);
+
+ exit(EXIT_FAILURE);
+ }
else
- current = first_selectable;
- free(w);
+ {
+ int found = 0;
+ char *word;
+
+ for (index = first_selectable; index <= last_selectable; index++)
+ {
+ if (word_a[index].orig != NULL)
+ word = word_a[index].orig;
+ else
+ word = word_a[index].str;
+
+ if (regexec(&re, word, (size_t) 0, NULL, 0) == 0)
+ {
+ current = index;
+ found = 1;
+ break;
+ }
+ }
+
+ if (!found)
+ current = first_selectable;
+ }
}
else if (*pre_selection_index != '\0')
{
- current = atoi(pre_selection_index);
- if (current >= count)
- current = count - 1;
- if (!word_a[current].is_selectable)
+ /* A prefix string or an index is expected */
+ /* """"""""""""""""""""""""""""""""""""""" */
+ size_t len;
+ char *ptr = pre_selection_index;
+
+ if (*ptr == '#')
{
- if (current > last_selectable)
+ /* An index is expected */
+ /* """""""""""""""""""" */
+ ptr++;
+
+ if (sscanf(ptr, "%d%n", &current, &len) == 1 && len == strlen(ptr))
+ {
+ /* We got an index (numeric value) */
+ /* """"""""""""""""""""""""""""""" */
+ if (current < 0)
+ current = first_selectable;
+
+ if (current >= count)
+ current = count - 1;
+
+ if (!word_a[current].is_selectable)
+ {
+ if (current > last_selectable)
+ current = last_selectable;
+ else if (current < first_selectable)
+ current = first_selectable;
+ else
+ while (current > first_selectable && !word_a[current].is_selectable)
+ current--;
+ }
+ }
+ else if (*ptr == '\0' || strcmp(ptr, "last") == 0)
+ /* We got a special index (empty or last) */
+ /* """""""""""""""""""""""""""""""""""""" */
current = last_selectable;
- else if (current < first_selectable)
- current = first_selectable;
else
- while (current > first_selectable && !word_a[current].is_selectable)
- current--;
+ {
+ fprintf(stderr, "Invalid index (%s)\n", ptr);
+
+ exit(EXIT_FAILURE);
+ }
+ }
+ else
+ {
+ /* A prefix is expected */
+ /* """""""""""""""""""" */
+ wchar_t *w;
+
+ new_current = last_selectable;
+ if (NULL != tst_prefix_search(tst, w = mb_strtowcs(ptr), tst_cb_cli))
+ current = new_current;
+ else
+ current = first_selectable;
+ free(w);
}
}
+ else
+ current = first_selectable;
/* We've finished reading from stdin */
/* we will now get the inputs from the controlling terminal if any */