[text] pretty-printing should work in the text view

pull/254/head
Timothy Stack 9 years ago
parent b4cb092ce1
commit 0d37a8c142

@ -30,6 +30,7 @@ lnav v0.8.0:
summary of the currently entered command.
Fixes:
* The pretty-print view should now work for text files.
* Nested fields in JSON logs are now supported for levels, bodies, etc...
* Tab-completion should work for quoted SQL identifiers.
* 'lo-fi' mode key shortcut changed to CTRL+L.

@ -183,7 +183,7 @@ Display
* - |ks| q |ke|
- Return to the previous view/quit
* - |ks| Shift |ke| + |ks| p |ke|
- Switch to/from the pretty-printed view of the displayed log messages
- Switch to/from the pretty-printed view of the displayed log or text files
* - |ks| Shift |ke| + |ks| t |ke|
- Display elapsed time between lines
* - |ks| t |ke|

@ -50,6 +50,7 @@ set(diag_STAT_SRCS
state-extension-functions.cc
strnatcmp.c
textview_curses.cc
timer.cc
view_curses.cc
views_vtab.cc
vt52_curses.cc
@ -112,6 +113,7 @@ set(diag_STAT_SRCS
termios_guard.hh
textfile_sub_source.hh
time_T.hh
timer.hh
top_status_source.hh
url_loader.hh
views_vtab.hh

@ -166,9 +166,9 @@ through the file.
>/< Move horizontally to the next/previous search hit.
P Switch to/from the pretty-printed view of the log messages
currently displayed. In this view, structured data, such
as XML, will be reformatted to make it easier to read.
P Switch to/from the pretty-printed view of the log or text
files currently displayed. In this view, structured data,
such as XML, will be reformatted to make it easier to read.
t Switch to/from the text file view. The text file view is
for any files that are not recognized as log files.

@ -817,13 +817,7 @@ void handle_paging_key(int ch)
break;
case 'P':
if (tc == &lnav_data.ld_views[LNV_PRETTY] ||
(lss && lss->text_line_count() > 0)) {
toggle_view(&lnav_data.ld_views[LNV_PRETTY]);
}
else {
lnav_data.ld_rl_view->set_value("Pretty-printed only works with log messages");
}
toggle_view(&lnav_data.ld_views[LNV_PRETTY]);
break;
case 't':

@ -757,14 +757,25 @@ static void open_schema_view(void)
static void open_pretty_view(void)
{
textview_curses *log_tc = &lnav_data.ld_views[LNV_LOG];
static const char *NOTHING_MSG =
"Nothing to pretty-print";
textview_curses *top_tc = lnav_data.ld_view_stack.top();
textview_curses *pretty_tc = &lnav_data.ld_views[LNV_PRETTY];
logfile_sub_source &lss = lnav_data.ld_log_source;
if (lss.text_line_count() > 0) {
ostringstream stream;
textview_curses *log_tc = &lnav_data.ld_views[LNV_LOG];
textview_curses *text_tc = &lnav_data.ld_views[LNV_TEXT];
ostringstream stream;
delete pretty_tc->get_sub_source();
if (top_tc->get_inner_height() == 0) {
pretty_tc->set_sub_source(new plain_text_source(NOTHING_MSG));
return;
}
if (top_tc == log_tc) {
logfile_sub_source &lss = lnav_data.ld_log_source;
bool first_line = true;
delete pretty_tc->get_sub_source();
for (vis_line_t vl = log_tc->get_top(); vl <= log_tc->get_bottom(); ++vl) {
content_line_t cl = lss.at(vl);
logfile *lf = lss.find(cl);
@ -784,15 +795,26 @@ static void open_pretty_view(void)
stream << trim(pp.print()) << endl;
first_line = false;
}
pretty_tc->set_sub_source(new plain_text_source(stream.str()));
if (lnav_data.ld_last_pretty_print_top != log_tc->get_top()) {
pretty_tc->set_top(vis_line_t(0));
}
else if (top_tc == text_tc) {
logfile *lf = lnav_data.ld_text_source.current_file();
for (vis_line_t vl = text_tc->get_top(); vl <= text_tc->get_bottom(); ++vl) {
logfile::iterator ll = lf->begin() + vl;
shared_buffer_ref sbr;
lf->read_full_message(ll, sbr);
data_scanner ds(sbr);
pretty_printer pp(&ds);
stream << pp.print() << endl;
}
lnav_data.ld_last_pretty_print_top = log_tc->get_top();
}
else {
log_warning("no log data to pretty-print");
pretty_tc->set_sub_source(new plain_text_source(stream.str()));
if (lnav_data.ld_last_pretty_print_top != log_tc->get_top()) {
pretty_tc->set_top(vis_line_t(0));
}
lnav_data.ld_last_pretty_print_top = log_tc->get_top();
redo_search(LNV_PRETTY);
}
@ -2795,7 +2817,7 @@ int main(int argc, char *argv[])
if (lnav_data.ld_flags & LNF_HEADLESS) {
std::vector<pair<string, string> > msgs;
std::vector<pair<string, string> >::iterator msg_iter;
textview_curses *log_tc, *tc;
textview_curses *log_tc, *text_tc, *tc;
attr_line_t al;
const std::string &line = al.get_string();
bool found_error = false;
@ -2809,7 +2831,14 @@ int main(int argc, char *argv[])
wait_for_pipers();
rebuild_indexes(true);
lnav_data.ld_views[LNV_LOG].set_top(vis_line_t(0));
log_tc->set_top(vis_line_t(0));
text_tc = &lnav_data.ld_views[LNV_TEXT];
text_tc->set_top(vis_line_t(0));
text_tc->set_height(vis_line_t(text_tc->get_inner_height()));
if (lnav_data.ld_log_source.text_line_count() == 0 &&
lnav_data.ld_text_source.text_line_count() > 0) {
toggle_view(&lnav_data.ld_views[LNV_TEXT]);
}
log_info("Executing initial commands");
execute_init_commands(msgs);

@ -41,6 +41,7 @@
#include <stack>
#include <deque>
#include <sstream>
#include <iomanip>
#include "timer.hh"
#include "ansi_scrubber.hh"
@ -65,7 +66,10 @@ public:
};
pretty_printer(data_scanner *ds)
: pp_depth(0), pp_line_length(0), pp_scanner(ds) {
: pp_leading_indent(0),
pp_depth(0),
pp_line_length(0),
pp_scanner(ds) {
this->pp_body_lines.push(0);
};
@ -118,11 +122,20 @@ public:
continue;
}
break;
case DT_WHITE:
if (this->pp_values.empty() && this->pp_depth == 0) {
this->pp_leading_indent = el.e_capture.length();
continue;
}
break;
default:
break;
}
this->pp_values.push_back(el);
}
while (this->pp_depth > 0) {
this->ascend();
}
this->flush_values();
return this->pp_stream.str();
@ -157,7 +170,7 @@ private:
break;
}
if (rc == 1 && reverse_lookup_enabled) {
const struct timeval timeout = {3, 0};
const struct timeval timeout = {0, 500 * 1000};
{
timer::interrupt_timer t(timeout, sigalrm_handler);
@ -238,13 +251,17 @@ private:
}
void append_indent() {
this->pp_stream << std::string(this->pp_leading_indent, ' ');
if (this->pp_stream.tellp() == this->pp_leading_indent) {
return;
}
for (int lpc = 0; lpc < this->pp_depth; lpc++) {
this->pp_stream << " ";
}
}
void write_element(const element &el) {
if (this->pp_depth > 0 && this->pp_line_length == 0 && el.e_token == DT_WHITE) {
if (this->pp_line_length == 0 && el.e_token == DT_WHITE) {
return;
}
if (this->pp_line_length == 0 && el.e_token == DT_LINE) {
@ -270,6 +287,7 @@ private:
}
}
int pp_leading_indent;
int pp_depth;
int pp_line_length;
std::stack<int> pp_body_lines;

@ -27,10 +27,12 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "config.h"
#include "timer.hh"
#include "lnav_log.hh"
const struct itimerval disable = {
static const struct itimerval DISABLE_TV = {
{ 0, 0 },
{ 0, 0 }
};
@ -39,20 +41,25 @@ timer::error::error(int err):e_err(err) { }
timer::interrupt_timer::interrupt_timer(struct timeval t,
sighandler_t_ sighandler=SIG_IGN) : new_handler(sighandler),
old_handler(NULL), new_val((struct itimerval){{0,0},t}),
old_val(disable), armed(false) { }
new_val((struct itimerval){{0,0},t}),
old_val(DISABLE_TV), armed(false) {
memset(&this->old_handler, 0, sizeof(this->old_handler));
}
int timer::interrupt_timer::arm_timer() {
struct sigaction sa;
// Disable the interval timer before setting the handler and arming the
// interval timer or else we will have a race-condition where the timer
// might fire and the appropriate handler might not be set.
if (setitimer(ITIMER_REAL, &disable, &this->old_val) != 0) {
if (setitimer(ITIMER_REAL, &DISABLE_TV, &this->old_val) != 0) {
log_error("Unable to disable the timer: %s",
strerror(errno));
return -1;
}
this->old_handler = signal(SIGALRM, this->new_handler);
if (this->old_handler == SIG_ERR) {
memset(&sa, 0, sizeof(sa));
sa.sa_handler = this->new_handler;
if (sigaction(SIGALRM, &sa, &this->old_handler) == -1) {
log_error("Unable to set the signal handler: %s",
strerror(errno));
if (setitimer(ITIMER_REAL, &this->old_val, NULL) != 0) {
@ -64,7 +71,7 @@ int timer::interrupt_timer::arm_timer() {
}
if (setitimer(ITIMER_REAL, &this->new_val, NULL) != 0) {
if(signal(SIGALRM, this->old_handler) == SIG_ERR) {
if(sigaction(SIGALRM, &this->old_handler, NULL) == -1) {
log_error("Unable to reset the signal handler: %s",
strerror(errno));
throw timer::error(errno);
@ -86,12 +93,12 @@ void timer::interrupt_timer::disarm_timer() {
// the previous interval timer or else we will have a race-condition
// where the timer might fire and the appropriate handler might not be
// set.
if (setitimer(ITIMER_REAL, &disable, NULL) != 0) {
if (setitimer(ITIMER_REAL, &DISABLE_TV, NULL) != 0) {
log_error("Failed to disable the timer: %s",
strerror(errno));
throw timer::error(errno);
}
if (signal(SIGALRM, this->old_handler) == SIG_ERR) {
if (sigaction(SIGALRM, &this->old_handler, NULL) == -1) {
log_error("Failed to reinstall previous SIGALRM handler: %s",
strerror(errno));
throw timer::error(errno);
@ -102,8 +109,8 @@ void timer::interrupt_timer::disarm_timer() {
throw timer::error(errno);
}
this->armed = false;
this->old_val = disable;
this->old_handler = NULL;
this->old_val = DISABLE_TV;
memset(&this->old_handler, 0, sizeof(this->old_handler));
}
}

@ -56,7 +56,8 @@ class interrupt_timer {
bool is_armed();
~interrupt_timer();
private:
sighandler_t_ new_handler, old_handler;
sighandler_t_ new_handler;
struct sigaction old_handler;
struct itimerval new_val, old_val;
bool armed;
};

@ -251,6 +251,8 @@ dist_noinst_DATA = \
logfile_with_a_really_long_name_to_test_a_bug_with_long_names.0 \
multiline.lnav \
mvwattrline_output.0 \
textfile_json_indented.0 \
textfile_json_one_line.0 \
view_colors_output.0 \
vt52_curses_input.0 \
vt52_curses_input.1 \

@ -355,6 +355,42 @@ check_output "pipe-line-to env vars are not working" <<EOF
EOF
run_test ${lnav_test} -n \
-c ":switch-to-view pretty" \
${test_dir}/textfile_json_one_line.0
check_output "pretty-printer is not working for text files" <<EOF
{
"foo bar" : null,
"array" : [
1,
2,
3
],
"obj" : {
"one" : 1,
"two" : true
}
}
EOF
run_test ${lnav_test} -n \
-c ":switch-to-view pretty" \
${test_dir}/textfile_json_one_line.0
check_output "pretty-printer is not working for indented text files" <<EOF
{
"foo bar": null,
"array": [
1,
2,
3
],
"obj": {
"one": 1,
"two": true
}
}
EOF
run_test ${lnav_test} -n \
-c ":switch-to-view pretty" \
${test_dir}/logfile_vami.0

@ -0,0 +1,12 @@
{
"foo bar": null,
"array": [
1,
2,
3
],
"obj": {
"one": 1,
"two": true
}
}

@ -0,0 +1 @@
{ "foo bar" : null, "array" : [1, 2, 3], "obj" : { "one" : 1, "two" : true } }
Loading…
Cancel
Save