[wrap] start support for word wrapping and fix a variety of glitches

pull/69/head
Timothy Stack 11 years ago
parent 50d50fb5a8
commit c3d51190c8

@ -189,6 +189,10 @@ public:
}
};
void invalidate() {
this->cleanup();
};
/** @param gpd The sink to send results to. */
void set_control(grep_proc_control *gpc)
{

@ -325,6 +325,9 @@ COMMANDS
Enable a inactive 'filter-in' or 'filter-out'
expression.
disable-word-wrap Disable word wrapping in the log and text file views.
enable-word-wrap Enable word wrapping in the log and text file views.
open <filename>[:<line>]
Open the given file within lnav and, if it is a
text file, switch to the text view and jump to
@ -348,7 +351,7 @@ COMMANDS
session <cmd> Add the given command to the session file
(~/.lnav/session). Any commands listed in the session file
are executed on startup. Only the highlight and
are executed on startup. Only the highlight, word-wrap, and
filter-related commands can be added to the session file.
create-logline-table <table-name>

@ -148,6 +148,10 @@ public:
int row,
string_attrs_t &value_out);
size_t text_size_for_line(textview_curses &tc, int row, bool raw) {
return 0;
};
int value_for_row(vis_line_t row)
{
int grow = row / (this->buckets_per_group() + 1);

@ -86,9 +86,14 @@ public:
// if false is returned, the merge is complete
bool get_top(owner_t *&owner, iterator_t& iterator)
{
owner = top_node_ptr_mbr->owner_ptr;
iterator = top_node_ptr_mbr->current_iterator;
return iterator != top_node_ptr_mbr->end_iterator;
if (top_node_ptr_mbr->has_iterator) {
owner = top_node_ptr_mbr->owner_ptr;
iterator = top_node_ptr_mbr->current_iterator;
return iterator != top_node_ptr_mbr->end_iterator;
}
else {
return false;
}
}
private:
@ -422,6 +427,7 @@ void kmerge_tree_c<T, owner_t, iterator_t, comparitor>::compare_nodes(kmerge_tre
node_rec* parent_ptr = node_ptr->parent_ptr;
parent_ptr->owner_ptr = winner_ptr->owner_ptr;
parent_ptr->has_iterator = winner_ptr->has_iterator;
parent_ptr->current_iterator = winner_ptr->current_iterator;
parent_ptr->end_iterator = winner_ptr->end_iterator;
parent_ptr->source_node_ptr = winner_ptr;

@ -49,6 +49,7 @@ listview_curses::listview_curses()
lv_height(0),
lv_needs_update(true),
lv_show_scrollbar(true),
lv_word_wrap(false),
lv_mouse_y(-1),
lv_mouse_mode(LV_MODE_NONE)
{ }
@ -102,12 +103,12 @@ bool listview_curses::handle_key(int ch)
case 'b':
case KEY_BACKSPACE:
case KEY_PPAGE:
this->shift_top(-height);
this->shift_top(-(this->rows_available(this->lv_top, RD_UP) - vis_line_t(1)));
break;
case ' ':
case KEY_NPAGE:
this->shift_top(height);
this->shift_top(this->rows_available(this->lv_top, RD_DOWN) - vis_line_t(1));
break;
case KEY_HOME:
@ -115,10 +116,9 @@ bool listview_curses::handle_key(int ch)
break;
case KEY_END: {
vis_line_t tail_bottom(this->get_inner_height() - height + 1);
vis_line_t last_line(this->get_inner_height() - 1);
vis_line_t tail_bottom(this->get_top_for_last_row());
tail_bottom = max(vis_line_t(0), tail_bottom);
if (this->get_top() == last_line)
this->set_top(tail_bottom);
else if (tail_bottom <= this->get_top())
@ -155,7 +155,7 @@ bool listview_curses::handle_key(int ch)
void listview_curses::do_update(void)
{
if (this->lv_window != NULL && this->lv_needs_update) {
vis_line_t y(this->lv_y), height, bottom, lines, row;
vis_line_t y(this->lv_y), height, bottom, row;
attr_line_t overlay_line;
vis_line_t overlay_height(0);
struct line_range lr;
@ -168,19 +168,13 @@ void listview_curses::do_update(void)
}
this->get_dimensions(height, width);
lr.lr_start = this->lv_left;
lr.lr_end = this->lv_left + width;
row_count = this->get_inner_height();
if (this->lv_top >= (int)row_count) {
this->lv_top = max(vis_line_t(0), vis_line_t(row_count) - height);
}
row = this->lv_top;
lines = min(height - overlay_height,
vis_line_t(row_count) - this->lv_top);
bottom = y + height;
for (; y < bottom; ++y) {
while (y < bottom) {
lr.lr_start = this->lv_left;
lr.lr_end = this->lv_left + width;
if (this->lv_overlay_source != NULL &&
this->lv_overlay_source->list_value_for_overlay(
*this,
@ -188,24 +182,31 @@ void listview_curses::do_update(void)
overlay_line)) {
this->mvwattrline(this->lv_window, y, 0, overlay_line, lr);
overlay_line.clear();
++y;
}
else if (lines > 0) {
else if (row < row_count) {
attr_line_t al;
this->lv_source->listview_value_for_row(*this, row, al);
this->mvwattrline(this->lv_window, y, 0, al, lr);
--lines;
do {
this->mvwattrline(this->lv_window, y, 0, al, lr);
lr.lr_start += width;
lr.lr_end += width;
++y;
} while (this->lv_word_wrap && y < bottom && lr.lr_start < al.length());
++row;
}
else {
wmove(this->lv_window, y, 0);
wclrtoeol(this->lv_window);
++y;
}
}
if (this->lv_show_scrollbar) {
double progress = 1.0;
double coverage = 1.0;
vis_line_t lines;
if (this->get_inner_height() > 0) {
progress = (double)this->lv_top / (double)row_count;

@ -66,6 +66,9 @@ public:
vis_line_t row,
attr_line_t &value_out) = 0;
virtual size_t listview_size_for_row(const listview_curses &lv,
vis_line_t row) = 0;
virtual std::string listview_source_name(const listview_curses &lv) {
return "";
};
@ -149,6 +152,49 @@ public:
void set_show_scrollbar(bool ss) { this->lv_show_scrollbar = ss; };
bool get_show_scrollbar() const { return this->lv_show_scrollbar; };
void set_word_wrap(bool ww) { this->lv_word_wrap = ww; };
bool get_word_wrap() const { return this->lv_word_wrap; };
enum row_direction_t {
RD_UP = -1,
RD_DOWN = 1,
};
vis_line_t rows_available(vis_line_t line, row_direction_t dir) {
unsigned long width;
vis_line_t height;
vis_line_t retval(0);
this->get_dimensions(height, width);
if (this->lv_word_wrap) {
size_t row_count = this->lv_source->listview_rows(*this);
while ((height > 0) && (line >= 0) && (line < row_count)) {
size_t len = this->lv_source->listview_size_for_row(*this, line);
do {
len -= std::min(width, len);
--height;
} while (len > 0);
line += vis_line_t(dir);
++retval;
}
}
else {
switch (dir) {
case RD_UP:
retval = std::min(height, line + vis_line_t(1));
break;
case RD_DOWN:
retval = std::min(height,
vis_line_t(this->lv_source->listview_rows(*this) - line));
break;
}
}
return retval;
};
/** @param win The curses window this view is attached to. */
void set_window(WINDOW *win) { this->lv_window = win; };
@ -192,12 +238,24 @@ public:
/** @return The line number that is displayed at the bottom. */
vis_line_t get_bottom()
{
vis_line_t retval, height;
unsigned long width;
vis_line_t retval = this->lv_top;
this->get_dimensions(height, width);
retval = std::min(this->lv_top + height - vis_line_t(1),
vis_line_t(this->get_inner_height() - 1));
retval += vis_line_t(this->rows_available(retval, RD_DOWN) - 1);
return retval;
};
vis_line_t get_top_for_last_row() {
vis_line_t retval(0);
if (this->get_inner_height() > 0) {
vis_line_t last_line(this->get_inner_height() - 1);
retval = last_line - vis_line_t(this->rows_available(last_line, RD_UP) - 1);
if ((retval + 1) < this->get_inner_height()) {
++retval;
}
}
return retval;
};
@ -259,7 +317,10 @@ public:
*/
unsigned int shift_left(int offset)
{
if (offset < 0 && this->lv_left < (unsigned int)-offset) {
if (this->lv_word_wrap) {
alerter::singleton().chime();
}
else if (offset < 0 && this->lv_left < (unsigned int)-offset) {
this->set_left(0);
}
else {
@ -353,6 +414,7 @@ protected:
* is needed.
*/
bool lv_show_scrollbar; /*< Draw the scrollbar in the view. */
bool lv_word_wrap;
struct timeval lv_mouse_time;
int lv_scroll_accel;

@ -529,10 +529,9 @@ void rebuild_indexes(bool force)
logfile_sub_source &lss = lnav_data.ld_log_source;
textview_curses & log_view = lnav_data.ld_views[LNV_LOG];
textview_curses & text_view = lnav_data.ld_views[LNV_TEXT];
vis_line_t old_bottom(0), height(0);
vis_line_t old_bottom(0);
content_line_t top_content = content_line_t(-1);
unsigned long width;
bool scroll_down;
size_t old_count;
time_t old_time;
@ -552,9 +551,8 @@ void rebuild_indexes(bool force)
bool new_data = false;
size_t new_count;
text_view.get_dimensions(height, width);
old_bottom = text_view.get_top() + height;
scroll_down = (size_t)old_bottom > tss->text_line_count();
old_bottom = text_view.get_top_for_last_row();
scroll_down = text_view.get_top() >= old_bottom;
for (iter = tss->tss_files.begin();
iter != tss->tss_files.end(); ) {
@ -619,15 +617,14 @@ void rebuild_indexes(bool force)
text_view.reload_data();
new_count = tss->text_line_count();
if (scroll_down && new_count >= (size_t)old_bottom) {
text_view.set_top(vis_line_t(new_count - height + 1));
if (scroll_down && text_view.get_top_for_last_row() > text_view.get_top()) {
text_view.set_top(text_view.get_top_for_last_row());
}
}
old_time = lnav_data.ld_top_time;
log_view.get_dimensions(height, width);
old_bottom = log_view.get_top() + height;
scroll_down = (size_t)old_bottom > old_count;
old_bottom = log_view.get_top_for_last_row();
scroll_down = log_view.get_top() >= old_bottom;
if (force) {
old_count = 0;
}
@ -638,8 +635,8 @@ void rebuild_indexes(bool force)
log_view.reload_data();
if (scroll_down && new_count >= (size_t)old_bottom) {
log_view.set_top(vis_line_t(new_count - height + 1));
if (scroll_down && log_view.get_top_for_last_row() > log_view.get_top()) {
log_view.set_top(log_view.get_top_for_last_row());
}
else if (!scroll_down && force) {
content_line_t new_top_content = content_line_t(-1);
@ -658,6 +655,9 @@ void rebuild_indexes(bool force)
start_line = force ? grep_line_t(0) : grep_line_t(-1);
if (force) {
if (lnav_data.ld_search_child[LNV_LOG].get() != NULL) {
lnav_data.ld_search_child[LNV_LOG]->get_grep_proc()->invalidate();
}
log_view.match_reset();
}
@ -707,6 +707,10 @@ public:
value_out = this->tds_lines[row];
};
size_t text_size_for_line(textview_curses &tc, int row, bool raw) {
return this->tds_lines[row].length();
};
private:
vector<string> tds_lines;
};
@ -1981,7 +1985,7 @@ void execute_search(lnav_view_t view, const std::string &regex)
}
gc.reset();
fprintf(stderr, "start search for: %s\n", regex.c_str());
fprintf(stderr, "start search for: '%s'\n", regex.c_str());
if (regex.empty()) {
lnav_data.ld_bottom_source.grep_error("");

@ -592,6 +592,36 @@ static string com_disable_filter(string cmdline, vector<string> &args)
return retval;
}
static string com_enable_word_wrap(string cmdline, vector<string> &args)
{
string retval = "";
if (args.size() == 0) {
}
else {
lnav_data.ld_views[LNV_LOG].set_word_wrap(true);
lnav_data.ld_views[LNV_TEXT].set_word_wrap(true);
}
return retval;
}
static string com_disable_word_wrap(string cmdline, vector<string> &args)
{
string retval = "";
if (args.size() == 0) {
}
else {
lnav_data.ld_views[LNV_LOG].set_word_wrap(false);
lnav_data.ld_views[LNV_TEXT].set_word_wrap(false);
}
return retval;
}
static std::vector<string> custom_logline_tables;
static string com_create_logline_table(string cmdline, vector<string> &args)
@ -656,14 +686,16 @@ static string com_session(string cmdline, vector<string> &args)
string retval = "error: expecting a command to save to the session file";
if (args.size() == 0) {}
else if (args.size() > 2) {
else if (args.size() >= 2) {
/* XXX put these in a map */
if (args[1] != "highlight" &&
args[1] != "enable-word-wrap" &&
args[1] != "disable-word-wrap" &&
args[1] != "filter-in" &&
args[1] != "filter-out" &&
args[1] != "enable-filter" &&
args[1] != "disable-filter") {
retval = "error: only the highlight and filter commands are "
retval = "error: only the highlight, filter, and word-wrap commands are "
"supported";
}
else if (getenv("HOME") == NULL) {
@ -1130,6 +1162,8 @@ void init_lnav_commands(readline_context::command_map_t &cmd_map)
cmd_map["write-csv-to"] = com_save_to;
cmd_map["enable-filter"] = com_enable_filter;
cmd_map["disable-filter"] = com_disable_filter;
cmd_map["enable-word-wrap"] = com_enable_word_wrap;
cmd_map["disable-word-wrap"] = com_disable_word_wrap;
cmd_map["create-logline-table"] = com_create_logline_table;
cmd_map["delete-logline-table"] = com_delete_logline_table;
cmd_map["open"] = com_open;

@ -225,6 +225,20 @@ public:
return retval;
};
size_t line_length(iterator ll) {
iterator next_line = ll + 1;
size_t retval;
if (next_line == this->end()) {
retval = this->lf_index_size - ll->get_offset();
}
else {
retval = next_line->get_offset() - ll->get_offset() - 1;
}
return retval;
};
void read_full_message(iterator ll, std::string &msg_out, int max_lines=50);
/**

@ -170,8 +170,6 @@ void logfile_sub_source::text_value_for_line(textview_curses &tc,
{
content_line_t line(0);
size_t tab;
assert(row >= 0);
assert((size_t)row < this->lss_index.size());
@ -189,10 +187,6 @@ void logfile_sub_source::text_value_for_line(textview_curses &tc,
this->lss_token_value =
this->lss_token_file->read_line(this->lss_token_line);
while ((tab = this->lss_token_value.find('\t')) != string::npos) {
this->lss_token_value = this->lss_token_value.replace(tab, 1, 8, ' ');
}
this->lss_token_date_end = 0;
value_out = this->lss_token_value;
if (this->lss_flags & F_SCRUB) {

@ -130,6 +130,14 @@ public:
int row,
string_attrs_t &value_out);
size_t text_size_for_line(textview_curses &tc, int row, bool raw) {
content_line_t line = this->lss_index[row];
logfile *lf = this->find(line);
logfile::iterator ll = lf->begin() + line;
return lf->line_length(ll) + (this->lss_flags & F_TIME_OFFSET ? 13 : 0);
};
void text_mark(bookmark_type_t *bm, int line, bool added)
{
content_line_t cl = this->lss_index[line];

@ -450,8 +450,9 @@ static void load_time_bookmarks(void)
continue;
}
if (part_name == NULL)
if (part_name == NULL) {
continue;
}
if (!dts.scan(log_time, NULL, &log_tm, log_tv)) {
continue;
@ -530,7 +531,7 @@ static void load_time_bookmarks(void)
lss.find(lf->get_filename().c_str(), base_content_line);
fprintf(stderr, "checking bookmarks for %s\n", lf->get_filename().c_str());
fprintf(stderr, "checking time offsets for %s\n", lf->get_filename().c_str());
logfile::iterator line_iter = lf->begin();
@ -687,7 +688,7 @@ static int read_last_search(yajlpp_parse_context *ypc, const unsigned char *str,
ypc->get_path_fragment(-2));
view_index = view_name - lnav_view_strings;
if (view_index < LNV__MAX) {
if (view_index < LNV__MAX && !regex.empty()) {
execute_search((lnav_view_t)view_index, regex);
lnav_data.ld_views[view_index].set_follow_search(false);
}
@ -786,6 +787,7 @@ static void save_time_bookmarks(void)
auto_mem<sqlite3_stmt> stmt(sqlite3_finalize);
if (sqlite3_open(db_path.c_str(), db.out()) != SQLITE_OK) {
fprintf(stderr, "error: unable to open bookmark DB -- %s\n", db_path.c_str());
return;
}
@ -813,7 +815,7 @@ static void save_time_bookmarks(void)
stmt.out(),
NULL) != SQLITE_OK) {
fprintf(stderr,
"error: could not prepare bookmark replace statemnt -- %s\n",
"error: could not prepare bookmark delete statemnt -- %s\n",
sqlite3_errmsg(db));
return;
}
@ -1065,7 +1067,7 @@ static void save_time_bookmarks(void)
}
if (sqlite3_bind_int64(stmt.in(), 6, offset.tv_usec) != SQLITE_OK) {
fprintf(stderr, "error: could not bind offset_sec -- %s\n",
fprintf(stderr, "error: could not bind offset_usec -- %s\n",
sqlite3_errmsg(db.in()));
return;
}

@ -410,7 +410,7 @@ void sql_strftime(char *buffer, size_t buffer_size, time_t time, int millis)
gmtime_r(&time, &gmtm);
snprintf(buffer, buffer_size,
"% 4d-%02d-%02dT%02d:%02d:%02d.%03d",
"%4d-%02d-%02dT%02d:%02d:%02d.%03d",
gmtm.tm_year + 1900,
gmtm.tm_mon + 1,
gmtm.tm_mday,

@ -81,6 +81,16 @@ public:
value_out[lr].insert(make_string_attr("file", this->current_file()));
};
size_t text_size_for_line(textview_curses &tc, int line, bool raw) {
size_t retval = 0;
if (!this->tss_files.empty()) {
retval = this->current_file()->line_length(this->current_file()->begin() + line);
}
return retval;
};
logfile *current_file(void) const
{
if (this->tss_files.empty()) {

@ -69,6 +69,8 @@ public:
std::string &value_out,
bool raw = false) = 0;
virtual size_t text_size_for_line(textview_curses &tc, int line, bool raw = false) = 0;
/**
* Inform the source that the given line has been marked/unmarked. This
* callback function can be used to translate between between visible line
@ -350,6 +352,10 @@ public:
vis_line_t line,
attr_line_t &value_out);
size_t listview_size_for_row(const listview_curses &lv, vis_line_t row) {
return this->tc_sub_source->text_size_for_line(*this, row);
};
std::string listview_source_name(const listview_curses &lv) {
return this->tc_sub_source == NULL ? "" :
this->tc_sub_source->text_source_name(*this);

@ -213,6 +213,8 @@ public:
/** @return The attributes for the string. */
string_attrs_t &get_attrs() { return this->al_attrs; };
size_t length() const { return this->al_string.length(); };
void operator=(const std::string &rhs) { this->al_string = rhs; };
/** Clear the string and the attributes for the string. */

@ -69,6 +69,10 @@ public:
}
};
size_t listview_size_for_row(const listview_curses &lv, vis_line_t row) {
return 100;
};
bool attrline_next_token(const view_curses &vc,
int line,
struct line_range &lr,

Loading…
Cancel
Save