Commit Diff


commit - 6b80b8fe2cc0cb093599c913eb911d403fa51cd5
commit + e7b982f4e861abb8fc0e18b12312d9b42add0da0
blob - dc7261e95b645d1344ea53c52b40114a74bbcec4
blob + 975edd75c7fe89c41633f24ed3fe632564fb42ba
--- ChangeLog
+++ ChangeLog
@@ -1,3 +1,11 @@
+2021-07-14  Omar Polo  <op@omarpolo.com>
+
+	* cmd.c (cmd_previous_completion): add previous-completion
+	(cmd_next_completion): add next-completion
+	(cmd_insert_current_candidate): add insert-current-candidate
+
+	* minibuffer.c (enter_minibuffer): support completions in minibuffer
+
 2021-07-13  Omar Polo  <op@omarpolo.com>
 
 	* pages.c: advertise B and F instead of C-M-b/C-M-f.
blob - 3c700286dfa06f282179020891c070f993c8960e
blob + b6ad63b2028b48b6fb393297b57713bd943c5252
--- cmd.c
+++ cmd.c
@@ -691,3 +691,54 @@ cmd_mini_next_history_element(struct buffer *buffer)
 	if (ministate.hist_cur != NULL)
 		buffer->current_line->line = ministate.hist_cur->h;
 }
+
+void
+cmd_previous_completion(struct buffer *buffer)
+{
+	if (in_minibuffer != MB_COMPREAD)
+		return;
+
+	buffer = &ministate.compl.buffer;
+
+	if (buffer->current_line != NULL)
+		buffer->current_line->parent->type = LINE_COMPL;
+
+	forward_line(buffer, -1);
+
+	if (buffer->current_line != NULL)
+		buffer->current_line->parent->type = LINE_COMPL_CURRENT;
+}
+
+void
+cmd_next_completion(struct buffer *buffer)
+{
+	if (in_minibuffer != MB_COMPREAD)
+		return;
+
+	buffer = &ministate.compl.buffer;
+
+	if (buffer->current_line != NULL)
+		buffer->current_line->parent->type = LINE_COMPL;
+
+	forward_line(buffer, +1);
+
+	if (buffer->current_line != NULL)
+		buffer->current_line->parent->type = LINE_COMPL_CURRENT;
+}
+
+void
+cmd_insert_current_candidate(struct buffer *buffer)
+{
+	struct vline *vl;
+
+	if (in_minibuffer != MB_COMPREAD)
+		return;
+
+	buffer = &ministate.compl.buffer;
+	if ((vl = buffer->current_line) == NULL)
+		return;
+
+	minibuffer_taint_hist();
+	strlcpy(ministate.buf, vl->parent->line, sizeof(ministate.buf));
+	ministate.buffer.cpoff = utf8_cplen(ministate.buf);
+}
blob - 3d74f7ac5de86741073d2bd73b382a3eff8ea6c1
blob + aefb7449c00ddc4a6c2a3df0770ae08df7cb1cf8
--- cmd.h
+++ cmd.h
@@ -64,3 +64,7 @@ CMD(cmd_mini_abort);
 CMD(cmd_mini_complete_and_exit);
 CMD(cmd_mini_previous_history_element);
 CMD(cmd_mini_next_history_element);
+
+CMD(cmd_previous_completion);
+CMD(cmd_next_completion);
+CMD(cmd_insert_current_candidate);
blob - 0e2930df2dcc09b3a90e40d8b4abb8ebe09390eb
blob + c365fe9e8145518418848b82d609e6fb127b4286
--- defaults.c
+++ defaults.c
@@ -42,6 +42,9 @@ struct lineprefix line_prefixes[] = {
 	[LINE_PRE_START] =	{ "```",	"   " },
 	[LINE_PRE_CONTENT] =	{ "",		"" },
 	[LINE_PRE_END] =	{ "```",	"```" },
+
+	[LINE_COMPL] =		{"", ""},
+	[LINE_COMPL_CURRENT] =	{"", ""},
 };
 
 struct line_face line_faces[] = {
@@ -100,6 +103,18 @@ struct line_face line_faces[] = {
 		.pair = PPEND,
 		.trail_pair = PPEND_TRAIL,
 	},
+
+	/* minibuffer */
+	[LINE_COMPL] = {
+		.prfx_pair = PCOMPL_PRFX,
+		.pair = PCOMPL,
+		.trail_pair = PCOMPL_TRAIL,
+	},
+	[LINE_COMPL_CURRENT] = {
+		.prfx_pair = PCOMPL_CURR_PRFX,
+		.pair = PCOMPL_CURR,
+		.trail_pair = PCOMPL_CURR_TRAIL,
+	},
 };
 
 struct tab_face tab_face = {
@@ -148,6 +163,10 @@ struct mapping {
 	{"pre.start",	LINE_PRE_START},
 	{"pre",		LINE_PRE_CONTENT},
 	{"pre.end",	LINE_PRE_END},
+
+	/* minibuffer */
+	{"compl",	LINE_COMPL},
+	{"compl.current", LINE_COMPL_CURRENT}
 };
 
 static struct mapping *
@@ -316,6 +335,10 @@ load_default_keys(void)
 	minibuffer_set_key("M-n",		cmd_mini_next_history_element);
 	minibuffer_set_key("<up>",		cmd_mini_previous_history_element);
 	minibuffer_set_key("<down>",		cmd_mini_next_history_element);
+
+	minibuffer_set_key("C-p",		cmd_previous_completion);
+	minibuffer_set_key("C-n",		cmd_next_completion);
+	minibuffer_set_key("tab",		cmd_insert_current_candidate);
 }
 
 void
@@ -334,6 +357,10 @@ config_init(void)
 
 	line_faces[LINE_LINK].fg = COLOR_BLUE;
 
+	line_faces[LINE_COMPL_CURRENT].prfx_bg = COLOR_CYAN;
+	line_faces[LINE_COMPL_CURRENT].bg = COLOR_CYAN;
+	line_faces[LINE_COMPL_CURRENT].trail_bg = COLOR_CYAN;
+
 	load_default_keys();
 }
 
blob - 00e7a2d4e24e1f49fbd241b3dacfecb83efeb8f1
blob + b48c7b920e5bc6656de8541757ee2a10396b029a
--- minibuffer.c
+++ minibuffer.c
@@ -52,11 +52,15 @@ void
 recompute_completions(int add)
 {
 	struct line	*l;
+	struct vline	*vl;
+	struct buffer	*b;
 
 	if (in_minibuffer != MB_COMPREAD)
 		return;
 
-	TAILQ_FOREACH(l, &ministate.compl.buffer.page.head, lines) {
+	b = &ministate.compl.buffer;
+	TAILQ_FOREACH(l, &b->page.head, lines) {
+		l->type = LINE_COMPL;
 		if (add && l->flags & L_HIDDEN)
 			continue;
 		if (strstr(l->line, ministate.buf) != NULL)
@@ -64,6 +68,13 @@ recompute_completions(int add)
 		else
 			l->flags |= L_HIDDEN;
 	}
+
+	if (b->current_line == NULL)
+		b->current_line = TAILQ_FIRST(&b->head);
+	b->current_line = adjust_line(b->current_line, b);
+	vl = b->current_line;
+	if (vl != NULL)
+		vl->parent->type = LINE_COMPL_CURRENT;
 }
 
 static void
@@ -252,23 +263,6 @@ read_select(void)
         exit_minibuffer();
 	minibuffer_hist_save_entry();
 	read_cb(ministate.buf, read_data);
-}
-
-/*
- * Just like erase_buffer, but don't call free(l->line);
- */
-static inline void
-erase_compl_buffer(struct buffer *buffer)
-{
-	struct line *l, *lt;
-
-	empty_vlist(buffer);
-
-	TAILQ_FOREACH_SAFE(l, &buffer->page.head, lines, lt) {
-		TAILQ_REMOVE(&buffer->page.head, l, lines);
-		/* don't free l->line! */
-		free(l);
-	}
 }
 
 /*
@@ -289,14 +283,18 @@ populate_compl_buffer(complfn *fn, void *data)
 		if ((l = calloc(1, sizeof(*l))) == NULL)
 			abort();
 
-		l->type = LINE_TEXT;
-		l->line = s;
+		l->type = LINE_COMPL;
+		if ((l->line = strdup(s)) == NULL)
+			abort();
 
 		if (TAILQ_EMPTY(&p->head))
 			TAILQ_INSERT_HEAD(&p->head, l, lines);
 		else
 			TAILQ_INSERT_TAIL(&p->head, l, lines);
 	}
+
+	if ((l = TAILQ_FIRST(&p->head)) != NULL)
+		l->type = LINE_COMPL_CURRENT;
 }
 
 void
@@ -308,8 +306,6 @@ enter_minibuffer(void (*self_insert_fn)(void), void (*
 	if (in_minibuffer == MB_COMPREAD) {
 		ui_schedule_redraw();
 
-		erase_compl_buffer(&ministate.compl.buffer);
-
 		ministate.compl.fn = complfn;
 		ministate.compl.data = compldata;
 		populate_compl_buffer(complfn, compldata);
@@ -336,8 +332,10 @@ enter_minibuffer(void (*self_insert_fn)(void), void (*
 void
 exit_minibuffer(void)
 {
-	if (in_minibuffer == MB_COMPREAD)
+	if (in_minibuffer == MB_COMPREAD) {
+		erase_buffer(&ministate.compl.buffer);
 		ui_schedule_redraw();
+	}
 
 	in_minibuffer = 0;
 	base_map = &global_map;
blob - 6094d777443a6653c4f61e751dbf4bb4c9409bbd
blob + f0fc7fb45a971d6dedbec80dfd427aa1793b9ba6
--- telescope.1
+++ telescope.1
@@ -338,6 +338,12 @@ mini-next-history-element
 mini-previous-history-element
 .It <down>
 mini-next-history-element
+.It C-p
+previous-completion
+.It C-n
+next-completion
+.It tab
+insert-current-candidate
 .El
 .Sh INTERACTIVE COMMANDS
 Follows the documentation for the interactive commands.
@@ -357,18 +363,24 @@ Move point to the end of the buffer.
 Move point one character forward.
 .It Ic forward-paragraph
 Move point one paragraph forward.
+.It Ic insert-current-candidate
+Copy the current selection text as minibuffer input.
 .It Ic move-beginning-of-line
 Move point at the beginning of the current (visual) line.
 .It Ic move-end-of-line
 Move point at the end of the current (visual) line.
 .It Ic next-button
 Move point to the next link.
+.It Ic next-completion
+Select the next completion.
 .It Ic next-heading
 Move point to the next heading.
 .It Ic next-line
 Move point to the next (visual) line, in the same column if possible.
 .It Ic previous-button
 Move point to the previous link.
+.It Ic previous-completion
+Select the previous completion.
 .It Ic previous-heading
 Move point to the previous heading.
 .It Ic previous-line
blob - 567cad0aab1a5abd4a3fe1246211bc6238ee54b7
blob + 8debbe52919cb97db7f39fdfc2c43aac905d1ade
--- telescope.h
+++ telescope.h
@@ -67,6 +67,7 @@ enum imsg_type {
 };
 
 enum line_type {
+	/* text/gemini */
 	LINE_TEXT,
 	LINE_LINK,
 	LINE_TITLE_1,
@@ -77,6 +78,10 @@ enum line_type {
 	LINE_PRE_START,
 	LINE_PRE_CONTENT,
 	LINE_PRE_END,
+
+	/* minibuffer */
+	LINE_COMPL,
+	LINE_COMPL_CURRENT,
 };
 
 /* for lines: mark as hidden */
@@ -94,7 +99,7 @@ struct line {
 };
 
 struct vline {
-	const struct line	*parent;
+	struct line		*parent;
 	char			*line;
 	int			 flags;
 	TAILQ_ENTRY(vline)	 vlines;
@@ -332,6 +337,7 @@ int		 imsg_compose_event(struct imsgev *, uint16_t, ui
 void		 erase_buffer(struct buffer *);
 void		 empty_linelist(struct buffer*);
 void		 empty_vlist(struct buffer*);
+int		 wrap_one(struct buffer *, const char *, struct line *, size_t);
 int		 wrap_text(struct buffer*, const char*, struct line*, size_t);
 int		 hardwrap_text(struct buffer*, struct line*, size_t);
 
blob - 540de79098f2017095d3d728b08ede7f01a69e79
blob + 52085730d675a0341c4c2f132d477c2585cb95c5
--- ui.c
+++ ui.c
@@ -415,6 +415,14 @@ wrap_page(struct buffer *buffer, int width)
 				pre_width = width;
 			hardwrap_text(buffer, l, pre_width);
 			break;
+		case LINE_COMPL:
+		case LINE_COMPL_CURRENT:
+			/*
+			 * TODO: should be width, but will break the
+			 * rendering.  Fix when unlocking completions
+			 * buffer from olivetti-mode.
+			 */
+			wrap_one(buffer, prfx, l, MIN(fill_column, width));
 		}
 
 		if (top_orig == l && buffer->top_line == NULL) {
@@ -601,7 +609,7 @@ redraw_tabline(void)
  * until the end of the buffer; if a visible line is not found, search
  * backward.  Return NULL if no viable line was found.
  */
-static inline struct vline *
+struct vline *
 adjust_line(struct vline *vl, struct buffer *buffer)
 {
 	struct vline *t;
@@ -692,7 +700,8 @@ again:
 			buffer->top_line = TAILQ_NEXT(buffer->top_line, vlines);
 		}
 
-		goto again;
+		if (vl != NULL)
+			goto again;
 	}
 
 	buffer->last_line_off = buffer->line_off;
blob - 909ba81917a545d6a5e0a29aaad82c3b3ee8f1f8
blob + e93980071fcbb4244679e7aaf91b2010dd57f27d
--- ui.h
+++ ui.h
@@ -72,6 +72,14 @@ enum pairs {
 	PPEND_PRFX,
 	PPEND_TRAIL,
 
+	PCOMPL_PRFX,
+	PCOMPL,
+	PCOMPL_TRAIL,
+
+	PCOMPL_CURR_PRFX,
+	PCOMPL_CURR,
+	PCOMPL_CURR_TRAIL,
+
 	PMODELINE,
 
 	PMINIBUF,
@@ -100,6 +108,7 @@ void		 ir_select(void);
 void		 lu_self_insert(void);
 void		 lu_select(void);
 void		 bp_select(void);
+struct vline	*adjust_line(struct vline *, struct buffer *);
 void		 vmessage(const char *, va_list);
 void		 message(const char *, ...) __attribute__((format(printf, 1, 2)));
 void		 start_loading_anim(struct tab *);
blob - 04dcedda1c3892437218f86acbe39043880f7986
blob + 33405b9289543ae349b444af2c524cc0a12e068d
--- wrap.c
+++ wrap.c
@@ -101,6 +101,32 @@ push_line(struct buffer *buffer, const struct line *l,
 }
 
 /*
+ * Similar to wrap_text, but emit only o vline.
+ */
+int
+wrap_one(struct buffer *buffer, const char *prfx, struct line *l, size_t width)
+{
+	struct vline *vl, *t;
+
+	/*
+	 * be lazy: call wrap_text and then discard the continuations.
+	 */
+
+	if (!wrap_text(buffer, prfx, l, width))
+		return 0;
+
+	TAILQ_FOREACH_SAFE(vl, &buffer->head, vlines, t) {
+		if (vl->flags & L_CONTINUATION) {
+			TAILQ_REMOVE(&buffer->head, vl, vlines);
+			free(vl->line);
+			free(vl);
+		}
+	}
+
+	return 1;
+}
+
+/*
  * Build a list of visual line by wrapping the given line, assuming
  * that when printed will have a leading prefix prfx.
  */