xC: normalize BSD Editline's history behaviour
Now it's a realistically useful frontend.
This commit is contained in:
		
							
								
								
									
										2
									
								
								NEWS
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								NEWS
									
									
									
									
									
								
							@@ -8,6 +8,8 @@ Unreleased
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 * xC: improved pager integration capabilities
 | 
					 * xC: improved pager integration capabilities
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 * xC: normalized editline's history behaviour, making it a viable frontend
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 * xC: made it show WALLOPS messages, as PRIVMSG for the server buffer
 | 
					 * xC: made it show WALLOPS messages, as PRIVMSG for the server buffer
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 * xD: implemented WALLOPS, choosing to make it target even non-operators
 | 
					 * xD: implemented WALLOPS, choosing to make it target even non-operators
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -77,9 +77,6 @@ Runtime dependencies: openssl +
 | 
				
			|||||||
Additionally for 'xC': curses, libffi, lua >= 5.3 (optional),
 | 
					Additionally for 'xC': curses, libffi, lua >= 5.3 (optional),
 | 
				
			||||||
                       readline >= 6.0 or libedit >= 2013-07-12
 | 
					                       readline >= 6.0 or libedit >= 2013-07-12
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Avoid libedit if you can, in general it works but at the moment history is
 | 
					 | 
				
			||||||
acting up and I have no clue about fixing it.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 $ git clone --recursive https://git.janouch.name/p/xK.git
 | 
					 $ git clone --recursive https://git.janouch.name/p/xK.git
 | 
				
			||||||
 $ mkdir xK/build
 | 
					 $ mkdir xK/build
 | 
				
			||||||
 $ cd xK/build
 | 
					 $ cd xK/build
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										3
									
								
								xC.adoc
									
									
									
									
									
								
							
							
						
						
									
										3
									
								
								xC.adoc
									
									
									
									
									
								
							@@ -114,8 +114,7 @@ _/usr/share/xC/plugins/_::
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
Bugs
 | 
					Bugs
 | 
				
			||||||
----
 | 
					----
 | 
				
			||||||
The editline (libedit) frontend is more of a proof of concept that mostly seems
 | 
					The editline (libedit) frontend may exhibit some unexpected behaviour.
 | 
				
			||||||
to work but exhibits bugs that are not our fault.
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
Reporting bugs
 | 
					Reporting bugs
 | 
				
			||||||
--------------
 | 
					--------------
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										53
									
								
								xC.c
									
									
									
									
									
								
							
							
						
						
									
										53
									
								
								xC.c
									
									
									
									
									
								
							@@ -761,6 +761,7 @@ struct input_el
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	struct input super;                 ///< Parent class
 | 
						struct input super;                 ///< Parent class
 | 
				
			||||||
	EditLine *editline;                 ///< The EditLine object
 | 
						EditLine *editline;                 ///< The EditLine object
 | 
				
			||||||
 | 
						FILE *null;                         ///< Output redirect
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bool active;                        ///< Are we a thing?
 | 
						bool active;                        ///< Are we a thing?
 | 
				
			||||||
	char *prompt;                       ///< The prompt we use
 | 
						char *prompt;                       ///< The prompt we use
 | 
				
			||||||
@@ -778,12 +779,12 @@ input_el__redisplay (void *input)
 | 
				
			|||||||
	// See rl_redisplay(), however NetBSD editline's map.c v1.54 breaks VREPRINT
 | 
						// See rl_redisplay(), however NetBSD editline's map.c v1.54 breaks VREPRINT
 | 
				
			||||||
	// so we bind redisplay somewhere else in app_editline_init()
 | 
						// so we bind redisplay somewhere else in app_editline_init()
 | 
				
			||||||
	struct input_el *self = input;
 | 
						struct input_el *self = input;
 | 
				
			||||||
	char x[] = { 'q' & 31, 0 };
 | 
						wchar_t x[] = { L'q' & 31, 0 };
 | 
				
			||||||
	el_push (self->editline, x);
 | 
						el_wpush (self->editline, x);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// We have to do this or it gets stuck and nothing is done
 | 
						// We have to do this or it gets stuck and nothing is done
 | 
				
			||||||
	int count = 0;
 | 
						int dummy_count = 0;
 | 
				
			||||||
	(void) el_wgets (self->editline, &count);
 | 
						(void) el_wgets (self->editline, &dummy_count);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static char *
 | 
					static char *
 | 
				
			||||||
@@ -1026,18 +1027,50 @@ input_el__restore (struct input_el *self)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 | 
					// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// XXX: Editline keeping its own history position (look for "eventno" there).
 | 
				
			||||||
 | 
					//   Invoking ed-next-history through our bind from app_editline_init() seems
 | 
				
			||||||
 | 
					//   like the only viable hack to get consistent history behaviour.
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					input_el__bottom (struct input_el *self)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						// First, we need to redirect output to avoid ringing the terminal bell.
 | 
				
			||||||
 | 
						FILE *out = NULL;
 | 
				
			||||||
 | 
						el_wget (self->editline, EL_GETFP, 1, &out);
 | 
				
			||||||
 | 
						el_wset (self->editline, EL_SETFP, 1, self->null);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Invoke hist_get() to make the history pointer's cursor match "eventno".
 | 
				
			||||||
 | 
						int down = 1, dummy_count = 0;
 | 
				
			||||||
 | 
						el_wpush (self->editline, L"\x1bn");
 | 
				
			||||||
 | 
						(void) el_wgets (self->editline, &dummy_count);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// It doesn't seem like we can just retrieve the position.
 | 
				
			||||||
 | 
						HistEventW ev;
 | 
				
			||||||
 | 
						while (!history_w (self->current->history, &ev, H_PREV))
 | 
				
			||||||
 | 
							down++;
 | 
				
			||||||
 | 
						while (down--)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							el_wpush (self->editline, L"\x1bn");
 | 
				
			||||||
 | 
							(void) el_wgets (self->editline, &dummy_count);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						el_wset (self->editline, EL_SETFP, 1, out);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void
 | 
					static void
 | 
				
			||||||
input_el_buffer_switch (void *input, input_buffer_t input_buffer)
 | 
					input_el_buffer_switch (void *input, input_buffer_t input_buffer)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct input_el *self = input;
 | 
						struct input_el *self = input;
 | 
				
			||||||
	struct input_el_buffer *buffer = input_buffer;
 | 
						struct input_el_buffer *buffer = input_buffer;
 | 
				
			||||||
 | 
						if (!self->active)
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (self->current)
 | 
						if (self->current)
 | 
				
			||||||
		input_el__save_buffer (self, self->current);
 | 
							input_el__save_buffer (self, self->current);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	input_el__restore_buffer (self, buffer);
 | 
					 | 
				
			||||||
	el_wset (self->editline, EL_HIST, history, buffer->history);
 | 
					 | 
				
			||||||
	self->current = buffer;
 | 
						self->current = buffer;
 | 
				
			||||||
 | 
						el_wset (self->editline, EL_HIST, history, buffer->history);
 | 
				
			||||||
 | 
						input_el__bottom (self);
 | 
				
			||||||
 | 
						input_el__restore_buffer (self, buffer);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void
 | 
					static void
 | 
				
			||||||
@@ -1111,7 +1144,7 @@ input_el_on_tty_readable (void *input)
 | 
				
			|||||||
	if (!buf || count-- <= 0)
 | 
						if (!buf || count-- <= 0)
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (count == 0 && buf[0] == ('D' - 0x40) /* hardcoded VEOF in editline */)
 | 
						if (count == 0 && buf[0] == ('D' - 0x40) /* hardcoded VEOF in el_wgets() */)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		el_deletestr (self->editline, 1);
 | 
							el_deletestr (self->editline, 1);
 | 
				
			||||||
		input_el__redisplay (self);
 | 
							input_el__redisplay (self);
 | 
				
			||||||
@@ -1131,6 +1164,7 @@ input_el_destroy (void *input)
 | 
				
			|||||||
		free (iter->help);
 | 
							free (iter->help);
 | 
				
			||||||
		ffi_closure_free (iter);
 | 
							ffi_closure_free (iter);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						fclose (self->null);
 | 
				
			||||||
	free (self->prompt);
 | 
						free (self->prompt);
 | 
				
			||||||
	free (self);
 | 
						free (self);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -1144,6 +1178,7 @@ input_el_new (void)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	struct input_el *self = xcalloc (1, sizeof *self);
 | 
						struct input_el *self = xcalloc (1, sizeof *self);
 | 
				
			||||||
	self->super.vtable = &input_el_vtable;
 | 
						self->super.vtable = &input_el_vtable;
 | 
				
			||||||
 | 
						self->null = fopen ("/dev/null", "w");
 | 
				
			||||||
	return &self->super;
 | 
						return &self->super;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -13908,13 +13943,10 @@ on_editline_return (EditLine *editline, int key)
 | 
				
			|||||||
	wchar_t *line = calloc (sizeof *info->buffer, len + 1);
 | 
						wchar_t *line = calloc (sizeof *info->buffer, len + 1);
 | 
				
			||||||
	memcpy (line, info->buffer, sizeof *info->buffer * len);
 | 
						memcpy (line, info->buffer, sizeof *info->buffer * len);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// XXX: Editline seems to remember its position in history,
 | 
					 | 
				
			||||||
	//   so it's not going to work as you'd expect it to
 | 
					 | 
				
			||||||
	if (*line)
 | 
						if (*line)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		HistEventW ev;
 | 
							HistEventW ev;
 | 
				
			||||||
		history_w (self->current->history, &ev, H_ENTER, line);
 | 
							history_w (self->current->history, &ev, H_ENTER, line);
 | 
				
			||||||
		print_debug ("history: %d %ls", ev.num, ev.str);
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	free (line);
 | 
						free (line);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -13926,6 +13958,7 @@ on_editline_return (EditLine *editline, int key)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	el_cursor (editline, len - point);
 | 
						el_cursor (editline, len - point);
 | 
				
			||||||
	el_wdeletestr (editline, len);
 | 
						el_wdeletestr (editline, len);
 | 
				
			||||||
 | 
						input_el__bottom (self);
 | 
				
			||||||
	return CC_REFRESH;
 | 
						return CC_REFRESH;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user