xC: normalize BSD Editline's history behaviour
Now it's a realistically useful frontend.
This commit is contained in:
		
							parent
							
								
									03d8ea4c5a
								
							
						
					
					
						commit
						c0996fcbe7
					
				
							
								
								
									
										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; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user