[hackers][vis][RFC][PATCH 0/2] Suggestion for basic autocomplete functionality
Heyhey I have implemented basic autocomplete functionality by sending the text at cursor position as a context to shell commands and dmenu. The user then chooses the autocompletion text he wants to use in dmenu which is then inserted at cursor position. Ideally the same approach should be used for code completion by sending some context to a code completion daemon (like gocode[0] for example). The daemon's output can then be sent to dmenu and selected by the user. The patches are still rough but I did not want to invest more time without knowing if such an approach would be considered for inclusion or not. Let me know what you think. Cheers, Silvan [0] https://github.com/nsf/gocode Silvan Jegen (2): Add autocompletion for current file contents Add autocompletion for file names config.def.h | 2 + main.c | 134 +++ vis.c| 6 ++- vis.h| 1 + 4 files changed, 142 insertions(+), 1 deletion(-) -- 2.8.2
[hackers][vis][RFC][PATCH 2/2] Add autocompletion for file names
We use the new infrastructure for autocompletion to implement autocompletion of file names within the working directory of vis. --- config.def.h | 1 + main.c | 20 2 files changed, 21 insertions(+) diff --git a/config.def.h b/config.def.h index 9e52102..5219d00 100644 --- a/config.def.h +++ b/config.def.h @@ -320,6 +320,7 @@ static const KeyBinding bindings_insert[] = { { "", ALIAS("") }, { "", ALIAS("")}, { "", ACTION(FILE_TEXT_AUTOCOMPLETE) }, + { "", ACTION(FILE_NAME_AUTOCOMPLETE) }, { "", ALIAS("")}, { "", ACTION(MODE_OPERATOR_PENDING) }, { "", ACTION(INSERT_REGISTER) }, diff --git a/main.c b/main.c index 9e224d1..e5807c9 100644 --- a/main.c +++ b/main.c @@ -131,6 +131,8 @@ static void insert_dialog_selection(Vis*, const char *cmdline, ...); static char *get_output_of_external_command(Vis*, const char *argv[]); /* Autocomplete input text at cursor based on the words in the current file */ static const char *autocomplete_file_text(Vis*, const char *keys, const Arg *arg); +/* Autocomplete input text at cursor based on file names of the current directory */ +static const char *autocomplete_file_name(Vis*, const char *keys, const Arg *arg); enum { VIS_ACTION_EDITOR_SUSPEND, @@ -314,6 +316,7 @@ enum { VIS_ACTION_OPEN_FILE_UNDER_CURSOR, VIS_ACTION_OPEN_FILE_UNDER_CURSOR_NEW_WINDOW, VIS_ACTION_FILE_TEXT_AUTOCOMPLETE, + VIS_ACTION_FILE_NAME_AUTOCOMPLETE, VIS_ACTION_NOP, }; @@ -1223,6 +1226,11 @@ static const KeyAction vis_action[] = { "Autocomplete text in file", autocomplete_file_text, }, + [VIS_ACTION_FILE_NAME_AUTOCOMPLETE] = { + "autocomplete-file-name", + "Autocomplete file name", + autocomplete_file_name, + }, [VIS_ACTION_NOP] = { "nop", "Ignore key, do nothing", @@ -2158,6 +2166,18 @@ static char *get_prefix_for_autocomplete(Vis *vis) { return prefix; } +static const char *autocomplete_file_name(Vis *vis, const char *keys, const Arg *arg) { + char *prefix = get_prefix_for_autocomplete(vis); + if (!prefix) + return keys; + + // TODO: get menu/dialog program to use from config? + insert_dialog_selection(vis, "ls | grep \"^%s\" | sort | dmenu | tr -d '\n' | sed \"s/%s//\"", prefix, prefix); + + free(prefix); + return keys; +} + static const char *autocomplete_file_text(Vis *vis, const char *keys, const Arg *arg) { Win *win = vis_window(vis); const char *fn = vis_window_filename(win); -- 2.8.2
[hackers][vis][RFC][PATCH 1/2] Add autocompletion for current file contents
We add some infrastructure in order to run a shell command and get its output which we then can insert into vis. This infrastructure we use to execute a shell command which sends all unique words of the current file to dmenu. The word selected in dmenu is then inserted into vis at all cursor positions. --- config.def.h | 1 + main.c | 114 +++ vis.c| 6 +++- vis.h| 1 + 4 files changed, 121 insertions(+), 1 deletion(-) diff --git a/config.def.h b/config.def.h index 8699136..9e52102 100644 --- a/config.def.h +++ b/config.def.h @@ -319,6 +319,7 @@ static const KeyBinding bindings_insert[] = { { "", ALIAS("<", ALIAS("") }, { "", ALIAS("")}, + { "", ACTION(FILE_TEXT_AUTOCOMPLETE) }, { "", ALIAS("")}, { "", ACTION(MODE_OPERATOR_PENDING) }, { "", ACTION(INSERT_REGISTER) }, diff --git a/main.c b/main.c index d0c0c73..9e224d1 100644 --- a/main.c +++ b/main.c @@ -125,6 +125,12 @@ static const char *percent(Vis*, const char *keys, const Arg *arg); static const char *number_increment_decrement(Vis*, const char *keys, const Arg *arg); /* open a filename under cursor in same (!arg->b) or new (arg->b) window */ static const char *open_file_under_cursor(Vis*, const char *keys, const Arg *arg); +/* Insert text chosen in external file dialog at cursor position(s) */ +static void insert_dialog_selection(Vis*, const char *cmdline, ...); +/* Get output of external command */ +static char *get_output_of_external_command(Vis*, const char *argv[]); +/* Autocomplete input text at cursor based on the words in the current file */ +static const char *autocomplete_file_text(Vis*, const char *keys, const Arg *arg); enum { VIS_ACTION_EDITOR_SUSPEND, @@ -307,6 +313,7 @@ enum { VIS_ACTION_NUMBER_DECREMENT, VIS_ACTION_OPEN_FILE_UNDER_CURSOR, VIS_ACTION_OPEN_FILE_UNDER_CURSOR_NEW_WINDOW, + VIS_ACTION_FILE_TEXT_AUTOCOMPLETE, VIS_ACTION_NOP, }; @@ -1211,6 +1218,11 @@ static const KeyAction vis_action[] = { "Open file under the cursor in a new window", open_file_under_cursor, { .b = true } }, + [VIS_ACTION_FILE_TEXT_AUTOCOMPLETE] = { + "autocomplete-file-text", + "Autocomplete text in file", + autocomplete_file_text, + }, [VIS_ACTION_NOP] = { "nop", "Ignore key, do nothing", @@ -2093,6 +2105,108 @@ static const char *open_file_under_cursor(Vis *vis, const char *keys, const Arg return keys; } +ssize_t read_buffer(void *context, char *data, size_t len) { + buffer_append(context, data, len); + return len; +} + +static char *get_output_of_external_command(Vis *vis, const char *argv[]) { + char *out = NULL; + Buffer bufout, buferr; + buffer_init(&bufout); + buffer_init(&buferr); + + Filerange empty = text_range_empty(); + int status = vis_pipe(vis, &empty, argv, &bufout, read_buffer, + &buferr, read_buffer); + + if (status != 0) { + vis_info_show(vis, "Command failed %s", buffer_content0(&buferr)); + } else { + out = malloc(bufout.len); + strncpy(out, buffer_content0(&bufout), buffer_length0(&bufout)); + out[buffer_length0(&bufout)] = '\0'; + } + + buffer_release(&bufout); + buffer_release(&buferr); + return out; +} + +// Caller has to free the allocated memory for the prefix +static char *get_prefix_for_autocomplete(Vis *vis) { + View *view = vis_view(vis); + Cursor *c = view_cursors(view); + Text *txt = vis_text(vis); + + Filerange r = text_object_word(txt, view_cursors_pos(c)-1); + if (!text_range_valid(&r)) + return NULL; + + char *prefix = text_bytes_alloc0(txt, r.start, text_range_size(&r)); + char *check; + for (check = prefix; *check; check++) { + if (!isspace(*check)) + break; + } + if (*check == '\0') { + vis_info_show(vis, "Autocompletion without prefix input is not valid."); + free(prefix); + return NULL; + } + + return prefix; +} + +static const char *autocomplete_file_text(Vis *vis, const char *keys, const Arg *arg) { + Win *win = vis_window(vis); + const char *fn = vis_window_filename(win); + + char *prefix = get_prefix_for_autocomplete(vis); + if (!prefix) + return keys; + + // TODO: get menu/dialog program to use from config? + insert_dialog_selection(vis, "cat '%s' | tr \" ;:$<>#?{}()[],.'\" '\n' | grep \"^
[hackers] [libzahl] Misc work on the manual || Mattias Andrée
commit d998ab149b65c2a8e85e30d9405ae19d4e2ec54a Author: Mattias Andrée AuthorDate: Mon May 16 18:01:44 2016 +0200 Commit: Mattias Andrée CommitDate: Mon May 16 18:01:44 2016 +0200 Misc work on the manual Signed-off-by: Mattias Andrée diff --git a/doc/bit-operations.tex b/doc/bit-operations.tex index 24e0155..c3fbe4a 100644 --- a/doc/bit-operations.tex +++ b/doc/bit-operations.tex @@ -1,7 +1,10 @@ \chapter{Bit operations} \label{chap:Bit operations} -TODO +libzahl provides a number of functions that operate on +bits. These can sometimes be used instead of arithmetic +functions for increased performance. You should read +the sections in order. \vspace{1cm} \minitoc @@ -11,7 +14,48 @@ TODO \section{Boundary} \label{sec:Boundary} -TODO % zbits zlsb +To retrieve the index of the lowest set bit, use + +\begin{alltt} + size_t zlsb(z_t a); +\end{alltt} + +\noindent +It will return a zero-based index, that is, if the +least significant bit is indeed set, it will return 0. + +If {\tt a} is a power of 2, it will return the power +of which 2 is raised, effectively calculating the +binary logarithm of {\tt a}. Note, this is only if +{\tt a} is a power of two. More generally, it returns +the number of trailing binary zeroes, if equivalently +the number of times {\tt a} can evenly be divided by +2. However, in the special case where $a = 0$, +{\tt SIZE\_MAX} is returned. + +A similar function is + +\begin{alltt} + size_t zbit(z_t a); +\end{alltt} + +\noindent +It returns the minimal number of bits require to +represent an integer. That is, $\lceil \log_2 a \rceil - 1$, +or equivalently, the number of times {\tt a} can be +divided by 2 before it gets the value 0. However, in +the special case where $a = 0$, 1 is returned. 0 is +never returned. If you want the value 0 to be returned +if $a = 0$, write + +\begin{alltt} + zzero(a) ? 0 : zbits(a) +\end{alltt} + +The definition ``it returns the minimal number +of bits required to represent an integer,'' +holds true if $a = 0$, the other divisions +do not hold true if $a = 0$. \newpage @@ -161,7 +205,28 @@ divide-and-conquer algorithms. \section{Bit manipulation} \label{sec:Bit manipulation} -TODO % zbset + +The function + +\begin{alltt} + zbset(z_t r, z_t a, size_t bit, int mode); +\end{alltt} + +\noindent +is used to manipulate single bits in {\tt a}. It will +copy {\tt a} into {\tt r} and then, in {\tt r}, either +set, clear, or flip, the bit with the index {\tt bit} +â the least significant bit has the index 0. The +action depend on the value of {\tt mode}: + +\begin{itemize} +\item +$mode > 0$ ($+1$): set +\item +$mode = 0$ ($0$): clear +\item +$mode < 0$ ($-1$): flip +\end{itemize} \newpage diff --git a/doc/not-implemented.tex b/doc/not-implemented.tex index 186a413..eacedea 100644 --- a/doc/not-implemented.tex +++ b/doc/not-implemented.tex @@ -399,7 +399,10 @@ using the following algorithm: \} zfree(k), zfree(a); \} +\end{alltt} +\newpage +\begin{alltt} void fib(z_t f, z_t n) \{ @@ -591,6 +594,11 @@ be improve by comparing character by character manually with using {\tt zxor}. +\newpage +\section{Miscellaneous} +\label{sec:Miscellaneous} + + \subsection{Character retrieval} \label{sec:Character retrieval} @@ -601,3 +609,76 @@ getu(z_t a) return zzero(a) ? 0 : a->chars[0]; \} \end{alltt} + +\subsection{Fit test} +\label{sec:Fit test} + +Some libraries have functions for testing +whether a big integer is small enough to +fit into an intrinsic type. Since libzahl +does not provide conversion to intrinsic +types this is irrelevant. But additionally, +it can be implemented with a single +one-line macro that does not have any +side-effects. + +\begin{alltt} + #define fits_in(a, type) (zbits(a) <= 8 * sizeof(type)) + \textcolor{c}{/* \textrm{Just be sure the type is integral.} */} +\end{alltt} + + +\subsection{Reference duplication} +\label{sec:Reference duplication} + +This could be useful for creating duplicates +with modified sign. But only if neither +{\tt r} or {\tt a} will be modified whilst +both are in use. Because it is unsafe, +fairly simple to create an implementation +with acceptable performance â {\tt *r = *a}, +â and probably seldom useful, this has not +be implemented. + +\begin{alltt} + int + refdup(z_t r, z_t a) + \{ + \textcolor{c}{/* \textrm{Almost fully optimised, but perfectly portable} *r = *a; */} + r->sign= a->sign; + r->used= a->used; + r->alloced = a->alloced; + r->chars = a->chars; + \} +\end{alltt} + + +\subsection{Variadic initialisation} +\label{sec:Variadic initialisation} + +Must bignum libraries have variadic functions +for initialisation and uninitialisation. This +is not available in libzahl, because it is +not useful enough and has performance overhead. +And what's next, support {\tt va\_list}, +variadic addition, variadic multiplication, +power towers, set manipulation? A
Re: [hackers][vis][RFC][PATCH 0/2] Suggestion for basic autocomplete functionality
On Mon, May 16, 2016 at 01:00:57PM +0200, Silvan Jegen wrote: > Heyhey > > I have implemented basic autocomplete functionality by sending the text > at cursor position as a context to shell commands and dmenu. The user > then chooses the autocompletion text he wants to use in dmenu which is > then inserted at cursor position. > > Ideally the same approach should be used for code completion by sending > some context to a code completion daemon (like gocode[0] for example). The > daemon's output can then be sent to dmenu and selected by the user. > > The patches are still rough but I did not want to invest more time > without knowing if such an approach would be considered for inclusion > or not. Let me know what you think. Just a couple of comments from glancing over the patches (I will have to take a closer look once I have more time): - use vis-menu (part of lattest git) as a wrapper around dmenu and slmenu - this should also work for unsaved or unnamed files, instead of using `cat filename` you should pipe the current file content to the external application - completion should probably be based on the primary (view_cursors_primary_get) not the the first cursor (view_cursors) Thanks, Marc -- Marc André Tanner >< http://www.brain-dump.org/ >< GPG key: 10C93617
[hackers] [dmenu][PATCH] Add incremental output.
http://tools.suckless.org/dmenu/patches/incremental This patch causes dmenu to print out the current text each time a key is pressed. Updated for current master branch. --- config.def.h | 1 + dmenu.1 | 4 dmenu.c | 11 +-- 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/config.def.h b/config.def.h index dcffd38..b879e9f 100644 --- a/config.def.h +++ b/config.def.h @@ -2,6 +2,7 @@ /* Default settings; can be overriden by command line. */ static int topbar = 1; /* -b option; if 0, dmenu appears at bottom */ +static int incremental = 0; /* -r option; if 1, dmenu outputs during input */ /* -fn option overrides fonts[0]; default X11 font or font set */ static const char *fonts[] = { "monospace:size=10" diff --git a/dmenu.1 b/dmenu.1 index d3ab805..0f7486e 100644 --- a/dmenu.1 +++ b/dmenu.1 @@ -6,6 +6,7 @@ dmenu \- dynamic menu .RB [ \-b ] .RB [ \-f ] .RB [ \-i ] +.RB [ \-r ] .RB [ \-l .RB [ \-m .IR monitor ] @@ -48,6 +49,9 @@ X until stdin reaches end\-of\-file. .B \-i dmenu matches menu items case insensitively. .TP +.B \-i +dmenu outputs text each time a key is pressed. +.TP .BI \-l " lines" dmenu lists items vertically, with the given number of lines. .TP diff --git a/dmenu.c b/dmenu.c index e0c2f80..100ab10 100644 --- a/dmenu.c +++ b/dmenu.c @@ -447,6 +447,11 @@ keypress(XKeyEvent *ev) match(); break; } + if(incremental) { + fprintf(stdout, "%s\n", text); + fflush(stdout); + } + drawmenu(); } @@ -610,7 +615,7 @@ setup(void) static void usage(void) { - fputs("usage: dmenu [-b] [-f] [-i] [-l lines] [-p prompt] [-fn font] [-m monitor]\n" + fputs("usage: dmenu [-b] [-f] [-i] [-r] [-l lines] [-p prompt] [-fn font] [-m monitor]\n" " [-nb color] [-nf color] [-sb color] [-sf color] [-v]\n", stderr); exit(1); } @@ -632,7 +637,9 @@ main(int argc, char *argv[]) else if (!strcmp(argv[i], "-i")) { /* case-insensitive item matching */ fstrncmp = strncasecmp; fstrstr = cistrstr; - } else if (i + 1 == argc) + } else if (!strcmp(argv[i], "-r")) /* outputs during input */ + incremental = 1; + else if (i + 1 == argc) usage(); /* these options take one argument */ else if (!strcmp(argv[i], "-l")) /* number of lines in vertical list */ -- 2.8.1