[hackers][vis][RFC][PATCH 0/2] Suggestion for basic autocomplete functionality

2016-05-16 Thread Silvan Jegen
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

2016-05-16 Thread Silvan Jegen
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

2016-05-16 Thread Silvan Jegen
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

2016-05-16 Thread git
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

2016-05-16 Thread Marc André Tanner
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.

2016-05-16 Thread koniu
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