Add an action to describe items
And improve the display of messages, separating any prefix out.
This commit is contained in:
		
							
								
								
									
										2
									
								
								NEWS
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								NEWS
									
									
									
									
									
								
							@@ -6,6 +6,8 @@ Unreleased
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 * Added a "z" binding to center the view on the selected item
 | 
					 * Added a "z" binding to center the view on the selected item
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 * Added a "?" binding to describe items in various tabs
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 * Made it possible to adjust the spectrum analyzer's FPS limit
 | 
					 * Made it possible to adjust the spectrum analyzer's FPS limit
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 * Fixed possibility of connection timeouts with PulseAudio integration
 | 
					 * Fixed possibility of connection timeouts with PulseAudio integration
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -36,6 +36,7 @@ PULSE_MUTE,         Toggle PulseAudio sink mute
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
CHOOSE,             Choose item
 | 
					CHOOSE,             Choose item
 | 
				
			||||||
DELETE,             Delete item
 | 
					DELETE,             Delete item
 | 
				
			||||||
 | 
					DESCRIBE,           Describe item
 | 
				
			||||||
UP,                 Go up a level
 | 
					UP,                 Go up a level
 | 
				
			||||||
MULTISELECT,        Toggle multiselect
 | 
					MULTISELECT,        Toggle multiselect
 | 
				
			||||||
INCREMENTAL_SEARCH, Incremental search
 | 
					INCREMENTAL_SEARCH, Incremental search
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										111
									
								
								nncmpp.c
									
									
									
									
									
								
							
							
						
						
									
										111
									
								
								nncmpp.c
									
									
									
									
									
								
							@@ -1298,6 +1298,7 @@ static struct app_context
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	struct poller_timer message_timer;  ///< Message timeout
 | 
						struct poller_timer message_timer;  ///< Message timeout
 | 
				
			||||||
	char *message;                      ///< Message to show in the statusbar
 | 
						char *message;                      ///< Message to show in the statusbar
 | 
				
			||||||
 | 
						char *message_detail;               ///< Non-emphasized part
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Connection:
 | 
						// Connection:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1700,6 +1701,7 @@ app_free_context (void)
 | 
				
			|||||||
	poller_curl_free (&g.poller_curl);
 | 
						poller_curl_free (&g.poller_curl);
 | 
				
			||||||
	poller_free (&g.poller);
 | 
						poller_free (&g.poller);
 | 
				
			||||||
	free (g.message);
 | 
						free (g.message);
 | 
				
			||||||
 | 
						free (g.message_detail);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (g.tk)
 | 
						if (g.tk)
 | 
				
			||||||
		termo_destroy (g.tk);
 | 
							termo_destroy (g.tk);
 | 
				
			||||||
@@ -2239,21 +2241,28 @@ static void
 | 
				
			|||||||
app_layout_statusbar (void)
 | 
					app_layout_statusbar (void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct layout l = {};
 | 
						struct layout l = {};
 | 
				
			||||||
 | 
						chtype attrs[2] = { APP_ATTR (NORMAL), APP_ATTR (HIGHLIGHT) };
 | 
				
			||||||
	if (g.message)
 | 
						if (g.message)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		app_push (&l, g.ui->padding (APP_ATTR (NORMAL), 0.25, 1))
 | 
							app_push (&l, g.ui->padding (attrs[0], 0.25, 1));
 | 
				
			||||||
			->id = WIDGET_MESSAGE;
 | 
							if (!g.message_detail)
 | 
				
			||||||
		app_push_fill (&l, g.ui->label (APP_ATTR (HIGHLIGHT), g.message))
 | 
								app_push_fill (&l, g.ui->label (attrs[1], g.message));
 | 
				
			||||||
			->id = WIDGET_MESSAGE;
 | 
							else
 | 
				
			||||||
		app_push (&l, g.ui->padding (APP_ATTR (NORMAL), 0.25, 1))
 | 
							{
 | 
				
			||||||
			->id = WIDGET_MESSAGE;
 | 
								app_push (&l, g.ui->label (attrs[1], g.message));
 | 
				
			||||||
 | 
								app_push_fill (&l, g.ui->label (attrs[0], g.message_detail));
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							app_push (&l, g.ui->padding (attrs[0], 0.25, 1));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		app_flush_layout (&l);
 | 
							app_flush_layout (&l);
 | 
				
			||||||
 | 
							LIST_FOR_EACH (struct widget, w, l.head)
 | 
				
			||||||
 | 
								w->id = WIDGET_MESSAGE;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	else if (g.editor.line)
 | 
						else if (g.editor.line)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		app_push (&l, g.ui->padding (APP_ATTR (NORMAL), 0.25, 1));
 | 
							app_push (&l, g.ui->padding (attrs[0], 0.25, 1));
 | 
				
			||||||
		app_push (&l, g.ui->editor (APP_ATTR (HIGHLIGHT)));
 | 
							app_push (&l, g.ui->editor (attrs[1]));
 | 
				
			||||||
		app_push (&l, g.ui->padding (APP_ATTR (NORMAL), 0.25, 1));
 | 
							app_push (&l, g.ui->padding (attrs[0], 0.25, 1));
 | 
				
			||||||
		app_flush_layout (&l);
 | 
							app_flush_layout (&l);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	else if (g.client.state == MPD_CONNECTED)
 | 
						else if (g.client.state == MPD_CONNECTED)
 | 
				
			||||||
@@ -2375,6 +2384,27 @@ app_move_selection (int diff)
 | 
				
			|||||||
	return result;
 | 
						return result;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					app_show_message (char *message, char *detail)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						cstr_set (&g.message, message);
 | 
				
			||||||
 | 
						cstr_set (&g.message_detail, detail);
 | 
				
			||||||
 | 
						poller_timer_set (&g.message_timer, 5000);
 | 
				
			||||||
 | 
						app_invalidate ();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					app_hide_message (void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (!g.message)
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						cstr_set (&g.message, NULL);
 | 
				
			||||||
 | 
						cstr_set (&g.message_detail, NULL);
 | 
				
			||||||
 | 
						poller_timer_reset (&g.message_timer);
 | 
				
			||||||
 | 
						app_invalidate ();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 | 
					// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void
 | 
					static void
 | 
				
			||||||
@@ -2558,17 +2588,6 @@ app_mpd_toggle (const char *name)
 | 
				
			|||||||
	return MPD_SIMPLE (name, value ? "0" : "1");
 | 
						return MPD_SIMPLE (name, value ? "0" : "1");
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void
 | 
					 | 
				
			||||||
app_hide_message (void)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	if (g.message)
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		cstr_set (&g.message, NULL);
 | 
					 | 
				
			||||||
		poller_timer_reset (&g.message_timer);
 | 
					 | 
				
			||||||
		app_invalidate ();
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static bool
 | 
					static bool
 | 
				
			||||||
app_process_action (enum action action)
 | 
					app_process_action (enum action action)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -2962,6 +2981,7 @@ g_normal_defaults[] =
 | 
				
			|||||||
	{ "Enter",      ACTION_CHOOSE             },
 | 
						{ "Enter",      ACTION_CHOOSE             },
 | 
				
			||||||
	{ "Delete",     ACTION_DELETE             },
 | 
						{ "Delete",     ACTION_DELETE             },
 | 
				
			||||||
	{ "d",          ACTION_DELETE             },
 | 
						{ "d",          ACTION_DELETE             },
 | 
				
			||||||
 | 
						{ "?",          ACTION_DESCRIBE           },
 | 
				
			||||||
	{ "M-Up",       ACTION_UP                 },
 | 
						{ "M-Up",       ACTION_UP                 },
 | 
				
			||||||
	{ "Backspace",  ACTION_UP                 },
 | 
						{ "Backspace",  ACTION_UP                 },
 | 
				
			||||||
	{ "v",          ACTION_MULTISELECT        },
 | 
						{ "v",          ACTION_MULTISELECT        },
 | 
				
			||||||
@@ -3238,6 +3258,12 @@ current_tab_on_action (enum action action)
 | 
				
			|||||||
		tab->item_mark = -1;
 | 
							tab->item_mark = -1;
 | 
				
			||||||
		return map && (id = compact_map_find (map, "id"))
 | 
							return map && (id = compact_map_find (map, "id"))
 | 
				
			||||||
			&& MPD_SIMPLE ("playid", id);
 | 
								&& MPD_SIMPLE ("playid", id);
 | 
				
			||||||
 | 
						case ACTION_DESCRIBE:
 | 
				
			||||||
 | 
							if (!map || !(id = compact_map_find (map, "file")))
 | 
				
			||||||
 | 
								return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							app_show_message (xstrdup ("Path: "), xstrdup (id));
 | 
				
			||||||
 | 
							return true;
 | 
				
			||||||
	case ACTION_DELETE:
 | 
						case ACTION_DELETE:
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		struct mpd_client *c = &g.client;
 | 
							struct mpd_client *c = &g.client;
 | 
				
			||||||
@@ -3652,6 +3678,12 @@ library_tab_on_action (enum action action)
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
		tab->item_mark = -1;
 | 
							tab->item_mark = -1;
 | 
				
			||||||
		return true;
 | 
							return true;
 | 
				
			||||||
 | 
						case ACTION_DESCRIBE:
 | 
				
			||||||
 | 
							if (!*x->path)
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							app_show_message (xstrdup ("Path: "), xstrdup (x->path));
 | 
				
			||||||
 | 
							return true;
 | 
				
			||||||
	case ACTION_UP:
 | 
						case ACTION_UP:
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		char *parent = library_tab_parent ();
 | 
							char *parent = library_tab_parent ();
 | 
				
			||||||
@@ -3990,6 +4022,9 @@ streams_tab_on_action (enum action action)
 | 
				
			|||||||
	case ACTION_MPD_ADD:
 | 
						case ACTION_MPD_ADD:
 | 
				
			||||||
		streams_tab_process (uri, false, &e);
 | 
							streams_tab_process (uri, false, &e);
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
 | 
						case ACTION_DESCRIBE:
 | 
				
			||||||
 | 
							app_show_message (xstrdup (uri), NULL);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
	default:
 | 
						default:
 | 
				
			||||||
		return false;
 | 
							return false;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -4103,17 +4138,26 @@ help_tab_on_action (enum action action)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	struct tab *tab = &g_help_tab.super;
 | 
						struct tab *tab = &g_help_tab.super;
 | 
				
			||||||
	if (tab->item_selected < 0
 | 
						if (tab->item_selected < 0
 | 
				
			||||||
	 || tab->item_selected >= (int) g_help_tab.actions_len
 | 
						 || tab->item_selected >= (int) g_help_tab.actions_len)
 | 
				
			||||||
	 || action != ACTION_CHOOSE)
 | 
					 | 
				
			||||||
		return false;
 | 
							return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	action = g_help_tab.actions[tab->item_selected];
 | 
						enum action a = g_help_tab.actions[tab->item_selected];
 | 
				
			||||||
	if (action == ACTION_NONE || action == ACTION_CHOOSE /* avoid recursion */)
 | 
						if (!a)
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (action == ACTION_DESCRIBE)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							char *name = xstrdup (g_action_names[a]);
 | 
				
			||||||
 | 
							cstr_transform (name, tolower_ascii);
 | 
				
			||||||
 | 
							app_show_message (xstrdup ("Configuration name: "), name);
 | 
				
			||||||
 | 
							return true;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (action != ACTION_CHOOSE || a == ACTION_CHOOSE /* avoid recursion */)
 | 
				
			||||||
		return false;
 | 
							return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// XXX: We can't propagate failure to ring the terminal/X11 bell, but we
 | 
						// XXX: We can't propagate failure to ring the terminal/X11 bell, but we
 | 
				
			||||||
	//   don't want to let our caller show a bad "can't do that" message either.
 | 
						//   don't want to let our caller show a bad "can't do that" message either.
 | 
				
			||||||
	return app_process_action (action), true;
 | 
						return app_process_action (a), true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void
 | 
					static void
 | 
				
			||||||
@@ -6078,11 +6122,8 @@ x11_process_press (int x, int y, int button, int modifiers)
 | 
				
			|||||||
	cstr_set (&g.x11_selection, text);
 | 
						cstr_set (&g.x11_selection, text);
 | 
				
			||||||
	XSetSelectionOwner (g.dpy, XInternAtom (g.dpy, "CLIPBOARD", False),
 | 
						XSetSelectionOwner (g.dpy, XInternAtom (g.dpy, "CLIPBOARD", False),
 | 
				
			||||||
		g.x11_window, CurrentTime);
 | 
							g.x11_window, CurrentTime);
 | 
				
			||||||
 | 
						app_show_message (xstrdup ("Text copied to clipboard: "),
 | 
				
			||||||
	cstr_set (&g.message,
 | 
							xstrdup (g.x11_selection));
 | 
				
			||||||
		xstrdup_printf ("Text copied to clipboard: %s", g.x11_selection));
 | 
					 | 
				
			||||||
	poller_timer_set (&g.message_timer, 5000);
 | 
					 | 
				
			||||||
	app_invalidate ();
 | 
					 | 
				
			||||||
	return true;
 | 
						return true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
out:
 | 
					out:
 | 
				
			||||||
@@ -6585,6 +6626,7 @@ app_on_message_timer (void *user_data)
 | 
				
			|||||||
	(void) user_data;
 | 
						(void) user_data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	cstr_set (&g.message, NULL);
 | 
						cstr_set (&g.message, NULL);
 | 
				
			||||||
 | 
						cstr_set (&g.message_detail, NULL);
 | 
				
			||||||
	app_invalidate ();
 | 
						app_invalidate ();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -6601,12 +6643,13 @@ app_log_handler (void *user_data, const char *quote, const char *fmt,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	struct str message = str_make ();
 | 
						struct str message = str_make ();
 | 
				
			||||||
	str_append (&message, quote);
 | 
						str_append (&message, quote);
 | 
				
			||||||
 | 
						size_t quote_len = message.len;
 | 
				
			||||||
	str_append_vprintf (&message, fmt, ap);
 | 
						str_append_vprintf (&message, fmt, ap);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Show it to the user, then maybe log it elsewhere as well.
 | 
						// Show it prettified to the user, then maybe log it elsewhere as well.
 | 
				
			||||||
	cstr_set (&g.message, xstrdup (message.str));
 | 
						message.str[0] = toupper_ascii (message.str[0]);
 | 
				
			||||||
	poller_timer_set (&g.message_timer, 5000);
 | 
						app_show_message (xstrndup (message.str, quote_len),
 | 
				
			||||||
	app_invalidate ();
 | 
							xstrdup (message.str + quote_len));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (g_verbose_mode && (g.ui != &tui_ui || !isatty (STDERR_FILENO)))
 | 
						if (g_verbose_mode && (g.ui != &tui_ui || !isatty (STDERR_FILENO)))
 | 
				
			||||||
		fprintf (stderr, "%s\n", message.str);
 | 
							fprintf (stderr, "%s\n", message.str);
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user