[ui] add back top status bar

This commit is contained in:
Timothy Stack 2022-07-14 22:32:38 -07:00
parent d1521496cc
commit f5cc4b298f
28 changed files with 296 additions and 170 deletions

9
NEWS
View File

@ -1,7 +1,12 @@
lnav v0.10.2:
Features:
* Redesigned the top status bar to make it display breadcrumbs that
are interactive. Pressing ENTER will activate the breadcrumb bar
* Redesigned the top status area to allow for user-specified
messages and added a second line that displays an interactive
breadcrumb bar. The top status line now shows the clock and
the remaining area displays whatever messages are inserted
into the lnav_user_notifications table. The information that
was originally on top is now in a second line and organized
as breadcrumbs. Pressing ENTER will activate the breadcrumb bar
and the left/right cursor keys can be used to select a particular
crumb while the up/down keys can select a value to switch to.
While a crumb is selected, you can also type in some text to do

View File

@ -560,6 +560,11 @@
"title": "/ui/theme-defs/<theme_name>/status-styles/subtitle",
"$ref": "#/definitions/style"
},
"info": {
"description": "Styling for informational messages in status bars",
"title": "/ui/theme-defs/<theme_name>/status-styles/info",
"$ref": "#/definitions/style"
},
"hotkey": {
"description": "Styling for hotkey highlights of status bars",
"title": "/ui/theme-defs/<theme_name>/status-styles/hotkey",

View File

@ -64,6 +64,7 @@ enum class role_t : int32_t {
VCR_ACTIVE_STATUS2, /*< */
VCR_STATUS_TITLE,
VCR_STATUS_SUBTITLE,
VCR_STATUS_INFO,
VCR_STATUS_STITCH_TITLE_TO_SUB,
VCR_STATUS_STITCH_SUB_TO_TITLE,
VCR_STATUS_STITCH_SUB_TO_NORMAL,

View File

@ -83,6 +83,8 @@ sql_progress(const struct log_cursor& lc)
if (ui_periodic_timer::singleton().time_to_update(sql_counter)) {
lnav_data.ld_bottom_source.update_loading(off, total);
lnav_data.ld_top_source.update_time();
lnav_data.ld_status[LNS_TOP].do_update();
lnav_data.ld_status[LNS_BOTTOM].do_update();
refresh();
}
@ -98,6 +100,8 @@ sql_progress_finished()
}
lnav_data.ld_bottom_source.update_loading(0, 0);
lnav_data.ld_top_source.update_time();
lnav_data.ld_status[LNS_TOP].do_update();
lnav_data.ld_status[LNS_BOTTOM].do_update();
lnav_data.ld_views[LNV_DB].redo_search();
}

View File

@ -15,12 +15,12 @@ efficiently zero in on problems.
## Opening Paths/URLs
The main arguments to lnav are the files, directories, glob patterns,
or URLs to be viewed. If no arguments are given, the default syslog
file for your system will be opened. These arguments will be polled
periodically so that any new data or files will be automatically
loaded. If a previously loaded file is removed or replaced, it will
be closed and the replacement opened.
The main arguments to lnav are the local/remote files, directories,
glob patterns, or URLs to be viewed. If no arguments are given, the
default syslog file for your system will be opened. These arguments
will be polled periodically so that any new data or files will be
automatically loaded. If a previously loaded file is removed or
replaced, it will be closed and the replacement opened.
Note: When opening SFTP URLs, if the password is not provided for the
host, the SSH agent can be used to do authentication.
@ -118,32 +118,59 @@ display has a proportionally sized 'scroll bar' that indicates your
current position in the files. The scroll bar will also show areas of
the file where warnings or errors are detected by coloring the bar
yellow or red, respectively. Tick marks will also be added to the
left and right hand side of the bar, for search hits and bookmarks.
left and right-hand side of the bar, for search hits and bookmarks.
A bar on the left side is color coded and broken up to indicate which
messages are from the same file. Pressing the left-arrow or `h` will
reveal the source file names for each message and pressing again will
show the full paths.
The bar on the left side indicates the file the log message is from. A
break in the bar means that the next log message comes from a different
file. The color of the bar is derived from the file name. Pressing the
left-arrow or `h` will reveal the source file names for each message and
pressing again will show the full paths.
Above and below the main body are status lines that display:
Above and below the main body are status lines that display a variety
of information. The top line displays:
* the current time;
* the name of the file the top line was pulled from;
* the log format for the top line;
* the current view;
* the line number for the top line in the display;
* the current search hit, the total number of hits, and the search term;
* The current time, configurable by the `/ui/clock-format` property.
* The highest priority message from the `lnav_user_notifications` table.
You can insert rows into this table to display your own status messages.
The default message displayed on startup explains how to focus on the
next status line at the top, which is an interactive breadcrumb bar.
The second status line at the top display breadcrumbs for the top line
in the main view. Pressing `ENTER` will focus input on the breadcrumb
bar, the cursor keys can be used to select a breadcrumb. The common
breadcrumbs are:
* The name of the current view.
* In the log view, the timestamp of the top log message.
* In the log view, the format of the log file the top log message is from.
* The name of the file the top line was pulled from.
* If the top line is within a larger chunk of structured data, the path to
the value in the top line will be shown.
Notes:
1. Pressing `CTRL-A`/`CTRL-E` will select the first/last breadcrumb.
1. Typing text while a breadcrumb is selected will perform a fuzzy
search on the possibilities.
The bottom status bar displays:
* The line number for the top line in the display.
* The current search hit, the total number of hits, and the search term.
If the view supports filtering, there will be a status line showing the
following:
* the number of enabled filters and the total number of filters;
* the number of lines not displayed because of filtering.
* The number of enabled filters and the total number of filters.
* The number of lines not displayed because of filtering.
To edit the filters, you can press TAB to change the focus from the main
view to the filter editor. The editor allows you to create, enable/disable,
and delete filters easily.
Along with filters, a "Files" panel will also be available for viewing
and controlling the files that lnav is currently monitoring.
Finally, the last line on the display is where you can enter search
patterns and execute internal commands, such as converting a
unix-timestamp into a human-readable date. The command-line is
@ -169,6 +196,7 @@ that you can always use `q` to pop the top view off of the stack.
| **q** | Leave the current view or quit the program when in the log file view. |
| Q | Similar to `q`, except it will try to sync the top time between the current and former views. For example, when leaving the spectrogram view with `Q`, the top time in that view will be matched to the top time in the log view. |
| TAB | Toggle focusing on the filter editor or the main view. |
| ENTER | Focus on the breadcrumb bar. |
| a/A | Restore the view that was previously popped with `q`/`Q`. The `A` hotkey will try to match the top times between the two views. |
| X | Close the current text file or log file. |

View File

@ -1,8 +1,9 @@
CREATE TABLE IF NOT EXISTS http_status_codes (
status integer PRIMARY KEY,
message text,
CREATE TABLE IF NOT EXISTS http_status_codes
(
status INTEGER PRIMARY KEY,
message TEXT,
FOREIGN KEY(status) REFERENCES access_log(sc_status)
FOREIGN KEY (status) REFERENCES access_log (sc_status)
);
INSERT INTO http_status_codes VALUES (100, 'Continue');
@ -65,33 +66,56 @@ INSERT INTO http_status_codes VALUES (508, 'Loop Detected');
INSERT INTO http_status_codes VALUES (510, 'Not Extended');
INSERT INTO http_status_codes VALUES (511, 'Network Authentication Required');
CREATE TABLE lnav_example_log (
log_line INTEGER PRIMARY KEY,
log_part TEXT collate naturalnocase,
log_time datetime,
log_actual_time datetime hidden,
log_idle_msecs int,
log_level TEXT collate loglevel,
log_mark boolean,
log_comment TEXT,
log_tags TEXT,
log_filters TEXT,
CREATE TABLE lnav_example_log
(
log_line INTEGER PRIMARY KEY,
log_part TEXT collate naturalnocase,
log_time datetime,
log_actual_time datetime hidden,
log_idle_msecs int,
log_level TEXT collate loglevel,
log_mark boolean,
log_comment TEXT,
log_tags TEXT,
log_filters TEXT,
ex_procname TEXT collate 'BINARY',
ex_duration INTEGER,
ex_procname TEXT collate 'BINARY',
ex_duration INTEGER,
log_time_msecs int hidden,
log_path TEXT hidden collate naturalnocase,
log_text TEXT hidden,
log_body TEXT hidden
log_time_msecs int hidden,
log_path TEXT hidden collate naturalnocase,
log_text TEXT hidden,
log_body TEXT hidden
);
CREATE VIEW lnav_top_view AS
SELECT * FROM lnav_views WHERE name = (
SELECT name FROM lnav_view_stack ORDER BY rowid DESC LIMIT 1);
SELECT *
FROM lnav_views
WHERE name = (SELECT name FROM lnav_view_stack ORDER BY rowid DESC LIMIT 1);
INSERT INTO lnav_example_log VALUES
(0, null, '2017-02-03T04:05:06.100', '2017-02-03T04:05:06.100', 0, 'info', 0, null, null, null, 'hw', 2, 1486094706000, '/tmp/log', '2017-02-03T04:05:06.100 hw(2): Hello, World!', 'Hello, World!'),
(1, null, '2017-02-03T04:05:06.200', '2017-02-03T04:05:06.200', 100, 'error', 0, null, null, null, 'gw', 4, 1486094706000, '/tmp/log', '2017-02-03T04:05:06.200 gw(4): Goodbye, World!', 'Goodbye, World!'),
(2, 'new', '2017-02-03T04:25:06.200', '2017-02-03T04:25:06.200', 1200000, 'warn', 0, null, null, null, 'gw', 1, 1486095906000, '/tmp/log', '2017-02-03T04:25:06.200 gw(1): Goodbye, World!', 'Goodbye, World!'),
(3, 'new', '2017-02-03T04:55:06.200', '2017-02-03T04:55:06.200', 1800000, 'debug', 0, null, null, null, 'gw', 10, 1486097706000, '/tmp/log', '2017-02-03T04:55:06.200 gw(10): Goodbye, World!', 'Goodbye, World!');
INSERT INTO lnav_example_log
VALUES (0, null, '2017-02-03T04:05:06.100', '2017-02-03T04:05:06.100', 0,
'info', 0, null, null, null, 'hw', 2, 1486094706000, '/tmp/log',
'2017-02-03T04:05:06.100 hw(2): Hello, World!', 'Hello, World!'),
(1, null, '2017-02-03T04:05:06.200', '2017-02-03T04:05:06.200', 100,
'error', 0, null, null, null, 'gw', 4, 1486094706000, '/tmp/log',
'2017-02-03T04:05:06.200 gw(4): Goodbye, World!', 'Goodbye, World!'),
(2, 'new', '2017-02-03T04:25:06.200', '2017-02-03T04:25:06.200', 1200000,
'warn', 0, null, null, null, 'gw', 1, 1486095906000, '/tmp/log',
'2017-02-03T04:25:06.200 gw(1): Goodbye, World!', 'Goodbye, World!'),
(3, 'new', '2017-02-03T04:55:06.200', '2017-02-03T04:55:06.200', 1800000,
'debug', 0, null, null, null, 'gw', 10, 1486097706000, '/tmp/log',
'2017-02-03T04:55:06.200 gw(10): Goodbye, World!', 'Goodbye, World!');
CREATE TABLE lnav_user_notifications
(
id TEXT NOT NULL DEFAULT 'org.lnav.unknown',
priority INTEGER NOT NULL DEFAULT 0,
created DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
expiration DATETIME DEFAULT NULL,
message TEXT
);
INSERT INTO lnav_user_notifications (id, priority, expiration, message)
VALUES ('org.lnav.breadcrumb.help.focus', -1, datetime('now', '+1 minute'),
'Press ENTER to focus on the breadcrumb bar');

View File

@ -583,8 +583,18 @@ void
listview_curses::set_selection(vis_line_t sel)
{
if (this->lv_selectable) {
if (this->lv_selection == sel) {
return;
}
if (sel == -1_vl) {
this->lv_selection = sel;
this->lv_source->listview_selection_changed(*this);
this->set_needs_update();
return;
}
auto inner_height = this->get_inner_height();
if (this->lv_selection != sel && sel >= 0_vl && sel < inner_height) {
if (sel >= 0_vl && sel < inner_height) {
auto found = false;
vis_line_t step;

View File

@ -1170,7 +1170,7 @@ looper()
vsb.push_back(sb);
breadcrumb_view.set_y(0);
breadcrumb_view.set_y(1);
breadcrumb_view.set_window(lnav_data.ld_window);
breadcrumb_view.set_line_source(lnav_crumb_source);
auto event_handler = [](auto&& tc) {
@ -1182,7 +1182,7 @@ looper()
};
for (lpc = 0; lpc < LNV__MAX; lpc++) {
lnav_data.ld_views[lpc].set_window(lnav_data.ld_window);
lnav_data.ld_views[lpc].set_y(1);
lnav_data.ld_views[lpc].set_y(2);
lnav_data.ld_views[lpc].set_height(
vis_line_t(-(rlc->get_height() + 1)));
lnav_data.ld_views[lpc].set_scroll_action(sb);
@ -1232,6 +1232,8 @@ looper()
lnav_data.ld_spectro_source->ss_exec_context
= &lnav_data.ld_exec_context;
lnav_data.ld_status[LNS_TOP].set_top(0);
lnav_data.ld_status[LNS_TOP].set_data_source(&lnav_data.ld_top_source);
lnav_data.ld_status[LNS_BOTTOM].set_top(-(rlc->get_height() + 1));
for (auto& sc : lnav_data.ld_status) {
sc.set_window(lnav_data.ld_window);
@ -1338,6 +1340,7 @@ looper()
gettimeofday(&current_time, nullptr);
lnav_data.ld_top_source.update_time(current_time);
lnav_data.ld_preview_view.set_needs_update();
layout_views();
@ -1444,6 +1447,7 @@ looper()
lnav_data.ld_spectro_details_view.do_update();
lnav_data.ld_user_message_view.do_update();
if (ui_clock::now() >= next_status_update_time) {
lnav_data.ld_top_source.update_user_msg();
for (auto& sc : lnav_data.ld_status) {
sc.do_update();
}
@ -1594,14 +1598,14 @@ looper()
next_rebuild_time = next_rescan_time;
}
ps->check_poll_set(pollfds);
lnav_data.ld_view_stack.top() |
[](auto tc) { lnav_data.ld_bottom_source.update_hits(tc); };
auto old_mode = lnav_data.ld_mode;
auto old_file_names_size
= lnav_data.ld_active_files.fc_file_names.size();
ps->check_poll_set(pollfds);
lnav_data.ld_view_stack.top() |
[](auto tc) { lnav_data.ld_bottom_source.update_hits(tc); };
if (lnav_data.ld_mode != old_mode) {
switch (lnav_data.ld_mode) {
case ln_mode_t::PAGING:

View File

@ -70,6 +70,7 @@
#include "sql_util.hh"
#include "statusview_curses.hh"
#include "textfile_sub_source.hh"
#include "top_status_source.hh"
#include "view_helpers.hh"
class spectrogram_source;
@ -92,6 +93,7 @@ extern const std::vector<std::string> lnav_zoom_strings;
/** The status bars. */
typedef enum {
LNS_TOP,
LNS_BOTTOM,
LNS_FILTER,
LNS_FILTER_HELP,
@ -195,6 +197,7 @@ struct lnav_data_t {
ln_mode_t ld_last_config_mode{ln_mode_t::FILTER};
statusview_curses ld_status[LNS__MAX];
top_status_source ld_top_source;
bottom_status_source ld_bottom_source;
filter_status_source ld_filter_status_source;
filter_help_status_source ld_filter_help_status_source;

View File

@ -81,6 +81,7 @@ do_observer_update(const std::shared_ptr<logfile>& lf)
if (isendwin()) {
return;
}
lnav_data.ld_top_source.update_time();
for (auto& sc : lnav_data.ld_status) {
sc.do_update();
}

View File

@ -768,6 +768,10 @@ static const struct json_path_container theme_status_styles_handlers = {
.with_description("Styling for subtitle sections of status bars")
.for_child(&lnav_theme::lt_style_status_subtitle)
.with_children(style_config_handlers),
yajlpp::property_handler("info")
.with_description("Styling for informational messages in status bars")
.for_child(&lnav_theme::lt_style_status_info)
.with_children(style_config_handlers),
yajlpp::property_handler("hotkey")
.with_description("Styling for hotkey highlights of status bars")
.for_child(&lnav_theme::lt_style_status_hotkey)

View File

@ -1,7 +1,7 @@
{
"$schema": "https://lnav.org/schemas/config-v1.schema.json",
"ui" : {
"clock-format": "%a %b %d %H:%M:%S %Z",
"clock-format": "%Y-%m-%dT%H:%M:%S %Z",
"dim-text": false,
"default-colors": true,
"keymap": "default",

View File

@ -183,6 +183,7 @@ struct lnav_theme {
style_config lt_style_status_title_hotkey;
style_config lt_style_status_disabled_title;
style_config lt_style_status_subtitle;
style_config lt_style_status_info;
style_config lt_style_status_hotkey;
style_config lt_style_quoted_code;
style_config lt_style_code_border;

View File

@ -204,6 +204,10 @@
"background-color": "#66d9ee",
"bold": true
},
"info": {
"color": "#aaa",
"background-color": "#353535"
},
"title-hotkey": {
"color": "$black",
"background-color": "#5394ec",

View File

@ -29,40 +29,28 @@
#include "top_status_source.hh"
#include <sqlite3.h>
#include "base/injector.hh"
#include "bound_tags.hh"
#include "config.h"
#include "lnav_config.hh"
#include "logfile_sub_source.hh"
#include "sql_util.hh"
top_status_source::top_status_source()
{
this->tss_fields[TSF_TIME].set_width(28);
this->tss_fields[TSF_PARTITION_NAME].set_width(34);
this->tss_fields[TSF_PARTITION_NAME].set_left_pad(1);
this->tss_fields[TSF_VIEW_NAME].set_width(8);
this->tss_fields[TSF_VIEW_NAME].set_role(role_t::VCR_STATUS_TITLE);
this->tss_fields[TSF_VIEW_NAME].right_justify(true);
this->tss_fields[TSF_STITCH_VIEW_FORMAT].set_width(2);
this->tss_fields[TSF_STITCH_VIEW_FORMAT].set_stitch_value(
role_t::VCR_STATUS_STITCH_SUB_TO_TITLE,
role_t::VCR_STATUS_STITCH_TITLE_TO_SUB);
this->tss_fields[TSF_STITCH_VIEW_FORMAT].right_justify(true);
this->tss_fields[TSF_FORMAT].set_width(20);
this->tss_fields[TSF_FORMAT].set_role(role_t::VCR_STATUS_SUBTITLE);
this->tss_fields[TSF_FORMAT].right_justify(true);
this->tss_fields[TSF_STITCH_FORMAT_FILENAME].set_width(2);
this->tss_fields[TSF_STITCH_FORMAT_FILENAME].set_stitch_value(
role_t::VCR_STATUS_STITCH_NORMAL_TO_SUB,
role_t::VCR_STATUS_STITCH_SUB_TO_NORMAL);
this->tss_fields[TSF_STITCH_FORMAT_FILENAME].right_justify(true);
this->tss_fields[TSF_FILENAME].set_min_width(35); /* XXX */
this->tss_fields[TSF_FILENAME].set_share(1);
this->tss_fields[TSF_FILENAME].right_justify(true);
this->tss_fields[TSF_TIME].set_role(role_t::VCR_STATUS_INFO);
this->tss_fields[TSF_USER_MSG].set_share(1);
this->tss_fields[TSF_USER_MSG].right_justify(true);
this->tss_fields[TSF_USER_MSG].set_role(role_t::VCR_STATUS_INFO);
}
void
top_status_source::update_time(const timeval& current_time)
{
status_field& sf = this->tss_fields[TSF_TIME];
auto& sf = this->tss_fields[TSF_TIME];
char buffer[32];
buffer[0] = ' ';
@ -82,64 +70,76 @@ top_status_source::update_time()
this->update_time(tv);
}
struct user_msg_stmt {
user_msg_stmt()
{
static const char* MSG_QUERY = R"(
SELECT message FROM lnav_user_notifications
WHERE expiration IS NULL OR expiration > datetime('now')
ORDER BY priority DESC
LIMIT 1
)";
auto& lnav_db = injector::get<auto_mem<sqlite3, sqlite_close_wrapper>&,
sqlite_db_tag>();
auto retcode = sqlite3_prepare_v2(
lnav_db, MSG_QUERY, -1, this->ums_stmt.out(), nullptr);
ensure(retcode == SQLITE_OK);
}
auto_mem<sqlite3_stmt> ums_stmt{sqlite3_finalize};
};
void
top_status_source::update_filename(listview_curses* lc)
top_status_source::update_user_msg()
{
auto& sf_partition = this->tss_fields[TSF_PARTITION_NAME];
auto& sf_format = this->tss_fields[TSF_FORMAT];
auto& sf_filename = this->tss_fields[TSF_FILENAME];
static user_msg_stmt um_stmt;
static auto& lnav_db
= injector::get<auto_mem<sqlite3, sqlite_close_wrapper>&,
sqlite_db_tag>();
if (lc->get_inner_height() > 0) {
std::vector<attr_line_t> rows(1);
auto& al = this->tss_fields[TSF_USER_MSG].get_value();
al.clear();
lc->get_data_source()->listview_value_for_rows(
*lc, lc->get_top(), rows);
auto& sa = rows[0].get_attrs();
auto file_attr_opt = get_string_attr(sa, logline::L_FILE);
if (file_attr_opt) {
auto lf = file_attr_opt.value().get();
auto* stmt = um_stmt.ums_stmt.in();
sqlite3_reset(stmt);
if (lf->get_format()) {
sf_format.set_value("% 13s",
lf->get_format()->get_name().get());
} else if (!lf->get_filename().empty()) {
sf_format.set_value("% 13s", "plain text");
} else {
sf_format.clear();
auto count = sqlite3_bind_parameter_count(stmt);
for (int lpc = 0; lpc < count; lpc++) {
const auto* name = sqlite3_bind_parameter_name(stmt, lpc + 1);
if (name[0] == '$') {
const char* env_value;
if ((env_value = getenv(&name[1])) != nullptr) {
sqlite3_bind_text(stmt, lpc + 1, env_value, -1, SQLITE_STATIC);
}
continue;
}
}
if (sf_filename.get_width() > (ssize_t) lf->get_filename().length())
{
sf_filename.set_value(lf->get_filename());
} else {
sf_filename.set_value(lf->get_unique_path());
auto step_res = sqlite3_step(stmt);
switch (step_res) {
case SQLITE_OK:
case SQLITE_DONE:
break;
case SQLITE_ROW: {
int ncols = sqlite3_column_count(stmt);
for (int lpc = 0; lpc < ncols; lpc++) {
const auto* text = (const char*) sqlite3_column_text(stmt, lpc);
al.with_ansi_string(text);
al.append(" ");
}
} else {
sf_format.clear();
sf_filename.clear();
break;
}
auto part_attr_opt = get_string_attr(sa, logline::L_PARTITION);
if (part_attr_opt) {
auto bm = part_attr_opt.value().get();
sf_partition.set_value(bm->bm_name.c_str());
} else {
sf_partition.clear();
}
} else {
sf_format.clear();
if (lc->get_data_source() != nullptr) {
sf_filename.set_value(
lc->get_data_source()->listview_source_name(*lc));
default: {
log_error("failed to execute user-message expression: %s",
sqlite3_errmsg(lnav_db));
break;
}
}
}
void
top_status_source::update_view_name(listview_curses* lc)
{
status_field& sf_view_name = this->tss_fields[TSF_VIEW_NAME];
sf_view_name.set_value("%s ", lc->get_title().c_str());
}

View File

@ -39,12 +39,7 @@ class top_status_source : public status_data_source {
public:
typedef enum {
TSF_TIME,
TSF_PARTITION_NAME,
TSF_VIEW_NAME,
TSF_STITCH_VIEW_FORMAT,
TSF_FORMAT,
TSF_STITCH_FORMAT_FILENAME,
TSF_FILENAME,
TSF_USER_MSG,
TSF__MAX
} field_t;
@ -62,9 +57,7 @@ public:
void update_time();
void update_filename(listview_curses* lc);
void update_view_name(listview_curses* lc);
void update_user_msg();
private:
status_field tss_fields[TSF__MAX];

View File

@ -879,6 +879,12 @@ view_colors::init_roles(const lnav_theme& lt,
lt.lt_style_status_subtitle,
lt.lt_style_status,
reporter);
this->vc_role_colors[lnav::enums::to_underlying(role_t::VCR_STATUS_INFO)]
= this->to_attrs(color_pair_base,
lt,
lt.lt_style_status_info,
lt.lt_style_status,
reporter);
this->vc_role_colors[lnav::enums::to_underlying(role_t::VCR_STATUS_HOTKEY)]
= this->to_attrs(color_pair_base,

View File

@ -1 +1 @@
/ui/clock-format = "%a %b %d %H:%M:%S %Z"
/ui/clock-format = "%Y-%m-%dT%H:%M:%S %Z"

View File

@ -1,3 +1,3 @@
/ui/clock-format = "%a %b %d %H:%M:%S %Z"
/ui/clock-format = "%Y-%m-%dT%H:%M:%S %Z"
info: changed config option -- /ui/clock-format
/ui/clock-format = "abc"

View File

@ -16,12 +16,12 @@ efficiently zero in on problems.
Opening Paths/URLs
The main arguments to lnav are the files, directories, glob patterns,
or URLs to be viewed. If no arguments are given, the default syslog
file for your system will be opened. These arguments will be polled
periodically so that any new data or files will be automatically
loaded. If a previously loaded file is removed or replaced, it will be
closed and the replacement opened.
The main arguments to lnav are the local/remote files, directories,
glob patterns, or URLs to be viewed. If no arguments are given, the
default syslog file for your system will be opened. These arguments
will be polled periodically so that any new data or files will be
automatically loaded. If a previously loaded file is removed or
replaced, it will be closed and the replacement opened.
Note: When opening SFTP URLs, if the password is not provided for the
host, the SSH agent can be used to do authentication.
@ -121,34 +121,66 @@ display has a proportionally sized 'scroll bar' that indicates your
current position in the files. The scroll bar will also show areas of
the file where warnings or errors are detected by coloring the bar
yellow or red, respectively. Tick marks will also be added to the left
and right hand side of the bar, for search hits and bookmarks.
and right-hand side of the bar, for search hits and bookmarks.
A bar on the left side is color coded and broken up to indicate which
messages are from the same file. Pressing the left-arrow or  h  will
reveal the source file names for each message and pressing again will
show the full paths.
The bar on the left side indicates the file the log message is from. A
break in the bar means that the next log message comes from a
different file. The color of the bar is derived from the file name.
Pressing the left-arrow or  h  will reveal the source file names for
each message and pressing again will show the full paths.
Above and below the main body are status lines that display:
Above and below the main body are status lines that display a variety
of information. The top line displays:
• the current time;
• the name of the file the top line was pulled from;
• the log format for the top line;
• the current view;
• the line number for the top line in the display;
• the current search hit, the total number of hits, and
the search term;
• The current time, configurable by the  /ui/clock-format 
property.
• The highest priority message from the  lnav_user_notifications 
table. You can insert rows into this table to display
your own status messages. The default message displayed
on startup explains how to focus on the next status line
at the top, which is an interactive breadcrumb bar.
The second status line at the top display breadcrumbs for the top line
in the main view. Pressing  ENTER  will focus input on the breadcrumb
bar, the cursor keys can be used to select a breadcrumb. The common
breadcrumbs are:
• The name of the current view.
• In the log view, the timestamp of the top log message.
• In the log view, the format of the log file the top log
message is from.
• The name of the file the top line was pulled from.
• If the top line is within a larger chunk of structured
data, the path to the value in the top line will be
shown.
Notes:
1. Pressing  CTRL-A / CTRL-E  will select the first/last
breadcrumb.
2. Typing text while a breadcrumb is selected will
perform a fuzzy search on the possibilities.
The bottom status bar displays:
• The line number for the top line in the display.
• The current search hit, the total number of hits, and
the search term.
If the view supports filtering, there will be a status line showing
the following:
• the number of enabled filters and the total number of
filters;
• the number of lines not displayed because of filtering.
• The number of enabled filters and the total number of
filters.
• The number of lines not displayed because of filtering.
To edit the filters, you can press TAB to change the focus from the
main view to the filter editor. The editor allows you to create,
enable/disable, and delete filters easily.
Along with filters, a "Files" panel will also be available for viewing
and controlling the files that lnav is currently monitoring.
Finally, the last line on the display is where you can enter search
patterns and execute internal commands, such as converting a
unix-timestamp into a human-readable date. The command-line is
@ -180,6 +212,7 @@ can always use  q  to pop the top view off of the stack.
top time in the log view.
TAB Toggle focusing on the filter editor or the main
view.
ENTER Focus on the breadcrumb bar.
a/A Restore the view that was previously popped with  q
/ Q . The  A  hotkey will try to match the top
times between the two views.

View File

@ -1,3 +1,3 @@
info: changed config option -- /ui/clock-format
info: reset option -- /ui/clock-format
/ui/clock-format = "%a %b %d %H:%M:%S %Z"
/ui/clock-format = "%Y-%m-%dT%H:%M:%S %Z"

View File

@ -1 +1 @@
error: sqlite3_exec failed -- lnav-error:{"level":"error","message":{"str":"call to readlink(path) failed","attrs":[{"start":8,"end":16,"type":"role","value":44},{"start":17,"end":21,"type":"role","value":43},{"start":8,"end":22,"type":"role","value":57}]},"reason":{"str":"unable to stat path: non-existent-link -- No such file or directory","attrs":[]},"snippets":[],"help":{"str":"","attrs":[]}}
error: sqlite3_exec failed -- lnav-error:{"level":"error","message":{"str":"call to readlink(path) failed","attrs":[{"start":8,"end":16,"type":"role","value":45},{"start":17,"end":21,"type":"role","value":44},{"start":8,"end":22,"type":"role","value":58}]},"reason":{"str":"unable to stat path: non-existent-link -- No such file or directory","attrs":[]},"snippets":[],"help":{"str":"","attrs":[]}}

View File

@ -1 +1 @@
error: sqlite3_exec failed -- lnav-error:{"level":"error","message":{"str":"call to realpath(path) failed","attrs":[{"start":8,"end":16,"type":"role","value":44},{"start":17,"end":21,"type":"role","value":43},{"start":8,"end":22,"type":"role","value":57}]},"reason":{"str":"Could not get real path for non-existent-path -- No such file or directory","attrs":[]},"snippets":[],"help":{"str":"","attrs":[]}}
error: sqlite3_exec failed -- lnav-error:{"level":"error","message":{"str":"call to realpath(path) failed","attrs":[{"start":8,"end":16,"type":"role","value":45},{"start":17,"end":21,"type":"role","value":44},{"start":8,"end":22,"type":"role","value":58}]},"reason":{"str":"Could not get real path for non-existent-path -- No such file or directory","attrs":[]},"snippets":[],"help":{"str":"","attrs":[]}}

View File

@ -1 +1 @@
error: sqlite3_exec failed -- lnav-error:{"level":"error","message":{"str":"call to json_contains(json, value) failed","attrs":[{"start":8,"end":21,"type":"role","value":44},{"start":22,"end":26,"type":"role","value":43},{"start":28,"end":33,"type":"role","value":43},{"start":8,"end":34,"type":"role","value":57}]},"reason":{"str":"parse error: premature EOF\n [\"hi\", \"bye\", \"solong]\n (right here) ------^","attrs":[]},"snippets":[],"help":{"str":"","attrs":[]}}
error: sqlite3_exec failed -- lnav-error:{"level":"error","message":{"str":"call to json_contains(json, value) failed","attrs":[{"start":8,"end":21,"type":"role","value":45},{"start":22,"end":26,"type":"role","value":44},{"start":28,"end":33,"type":"role","value":44},{"start":8,"end":34,"type":"role","value":58}]},"reason":{"str":"parse error: premature EOF\n [\"hi\", \"bye\", \"solong]\n (right here) ------^","attrs":[]},"snippets":[],"help":{"str":"","attrs":[]}}

View File

@ -1 +1 @@
error: sqlite3_exec failed -- lnav-error:{"level":"error","message":{"str":"call to regexp_match(re, str) failed","attrs":[{"start":8,"end":20,"type":"role","value":44},{"start":21,"end":23,"type":"role","value":43},{"start":25,"end":28,"type":"role","value":43},{"start":8,"end":29,"type":"role","value":57}]},"reason":{"str":"regular expression does not have any captures","attrs":[]},"snippets":[],"help":{"str":"","attrs":[]}}
error: sqlite3_exec failed -- lnav-error:{"level":"error","message":{"str":"call to regexp_match(re, str) failed","attrs":[{"start":8,"end":20,"type":"role","value":45},{"start":21,"end":23,"type":"role","value":44},{"start":25,"end":28,"type":"role","value":44},{"start":8,"end":29,"type":"role","value":58}]},"reason":{"str":"regular expression does not have any captures","attrs":[]},"snippets":[],"help":{"str":"","attrs":[]}}

View File

@ -1 +1 @@
error: sqlite3_exec failed -- lnav-error:{"level":"error","message":{"str":"call to timeslice(time, slice) failed","attrs":[{"start":8,"end":17,"type":"role","value":44},{"start":18,"end":22,"type":"role","value":43},{"start":24,"end":29,"type":"role","value":43},{"start":8,"end":30,"type":"role","value":57}]},"reason":{"str":"unable to parse time slice value: blah -- Unrecognized input","attrs":[]},"snippets":[],"help":{"str":"","attrs":[]}}
error: sqlite3_exec failed -- lnav-error:{"level":"error","message":{"str":"call to timeslice(time, slice) failed","attrs":[{"start":8,"end":17,"type":"role","value":45},{"start":18,"end":22,"type":"role","value":44},{"start":24,"end":29,"type":"role","value":44},{"start":8,"end":30,"type":"role","value":58}]},"reason":{"str":"unable to parse time slice value: blah -- Unrecognized input","attrs":[]},"snippets":[],"help":{"str":"","attrs":[]}}

View File

@ -1 +1 @@
error: sqlite3_exec failed -- lnav-error:{"level":"error","message":{"str":"call to timeslice(time, slice) failed","attrs":[{"start":8,"end":17,"type":"role","value":44},{"start":18,"end":22,"type":"role","value":43},{"start":24,"end":29,"type":"role","value":43},{"start":8,"end":30,"type":"role","value":57}]},"reason":{"str":"no time slice value given","attrs":[]},"snippets":[],"help":{"str":"","attrs":[]}}
error: sqlite3_exec failed -- lnav-error:{"level":"error","message":{"str":"call to timeslice(time, slice) failed","attrs":[{"start":8,"end":17,"type":"role","value":45},{"start":18,"end":22,"type":"role","value":44},{"start":24,"end":29,"type":"role","value":44},{"start":8,"end":30,"type":"role","value":58}]},"reason":{"str":"no time slice value given","attrs":[]},"snippets":[],"help":{"str":"","attrs":[]}}

View File

@ -888,7 +888,7 @@ CREATE TABLE lnav_events (
ts TEXT NOT NULL DEFAULT(strftime('%Y-%m-%dT%H:%M:%f', 'now')),
content TEXT
);
CREATE TABLE http_status_codes (
CREATE TABLE http_status_codes
EOF