1
1
mirror of https://github.com/tstack/lnav.git synced 2024-09-11 13:05:51 +03:00

copy search terms to OS-Xs find clipboard

Fixes #108
This commit is contained in:
Timothy Stack 2014-11-19 06:12:43 -08:00
parent 80ef38227b
commit 6a90dd9bc2
8 changed files with 182 additions and 40 deletions

3
NEWS
View File

@ -6,6 +6,9 @@ lnav v0.7.2:
and write-csv-to commands will also write their output to the terminal
when passed '-' as the file name. This mode can be useful for copying
plain text lines to the clipboard.
* (OS X) Text search strings are copied to the system's "find" clipboard.
Also, when starting a new search, the current value in the "find"
clipboard can be tab-completed.
lnav v0.7.1:
Features:

View File

@ -36,6 +36,7 @@ set(diag_STAT_SRCS
sqlite-extension-func.c
statusview_curses.cc
string-extension-functions.cc
sysclip.cc
pcrepp.cc
piper_proc.cc
sql_util.cc
@ -87,6 +88,7 @@ set(diag_STAT_SRCS
sequence_sink.hh
status_controllers.hh
strong_int.hh
sysclip.hh
term_extra.hh
termios_guard.hh
textfile_sub_source.hh

View File

@ -124,6 +124,7 @@ noinst_HEADERS = \
statusview_curses.hh \
strnatcmp.h \
strong_int.hh \
sysclip.hh \
termios_guard.hh \
term_extra.hh \
textfile_sub_source.hh \
@ -192,6 +193,7 @@ libdiag_a_SOURCES = \
sql_util.cc \
state-extension-functions.cc \
strnatcmp.c \
sysclip.cc \
textview_curses.cc \
time_fmts.cc \
view_curses.cc \

View File

@ -130,14 +130,15 @@ am_libdiag_a_OBJECTS = ansi_scrubber.$(OBJEXT) bookmarks.$(OBJEXT) \
string-extension-functions.$(OBJEXT) pcrepp.$(OBJEXT) \
piper_proc.$(OBJEXT) sql_util.$(OBJEXT) \
state-extension-functions.$(OBJEXT) strnatcmp.$(OBJEXT) \
textview_curses.$(OBJEXT) time_fmts.$(OBJEXT) \
view_curses.$(OBJEXT) vt52_curses.$(OBJEXT) \
log_vtab_impl.$(OBJEXT) xterm_mouse.$(OBJEXT) yajlpp.$(OBJEXT) \
yajl/yajl.$(OBJEXT) yajl/yajl_alloc.$(OBJEXT) \
yajl/yajl_buf.$(OBJEXT) yajl/yajl_encode.$(OBJEXT) \
yajl/yajl_gen.$(OBJEXT) yajl/yajl_lex.$(OBJEXT) \
yajl/yajl_parser.$(OBJEXT) yajl/yajl_tree.$(OBJEXT) \
yajl/yajl_version.$(OBJEXT) spookyhash/SpookyV2.$(OBJEXT)
sysclip.$(OBJEXT) textview_curses.$(OBJEXT) \
time_fmts.$(OBJEXT) view_curses.$(OBJEXT) \
vt52_curses.$(OBJEXT) log_vtab_impl.$(OBJEXT) \
xterm_mouse.$(OBJEXT) yajlpp.$(OBJEXT) yajl/yajl.$(OBJEXT) \
yajl/yajl_alloc.$(OBJEXT) yajl/yajl_buf.$(OBJEXT) \
yajl/yajl_encode.$(OBJEXT) yajl/yajl_gen.$(OBJEXT) \
yajl/yajl_lex.$(OBJEXT) yajl/yajl_parser.$(OBJEXT) \
yajl/yajl_tree.$(OBJEXT) yajl/yajl_version.$(OBJEXT) \
spookyhash/SpookyV2.$(OBJEXT)
libdiag_a_OBJECTS = $(am_libdiag_a_OBJECTS)
am__installdirs = "$(DESTDIR)$(bindir)"
PROGRAMS = $(bin_PROGRAMS) $(noinst_PROGRAMS)
@ -456,6 +457,7 @@ noinst_HEADERS = \
statusview_curses.hh \
strnatcmp.h \
strong_int.hh \
sysclip.hh \
termios_guard.hh \
term_extra.hh \
textfile_sub_source.hh \
@ -524,6 +526,7 @@ libdiag_a_SOURCES = \
sql_util.cc \
state-extension-functions.cc \
strnatcmp.c \
sysclip.cc \
textview_curses.cc \
time_fmts.cc \
view_curses.cc \
@ -783,6 +786,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/statusview_curses.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/string-extension-functions.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/strnatcmp.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sysclip.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_override.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/textview_curses.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/time_fmts.Po@am__quote@

View File

@ -221,6 +221,7 @@ throw (error)
/* Still need more space, try a realloc. */
old = this->lb_buffer.release();
this->lb_share_manager.invalidate_refs();
tmp = (char *)realloc(old, new_max);
if (tmp != NULL) {
this->lb_buffer = tmp;
@ -250,7 +251,6 @@ throw (error)
* The request is outside the cached range, need to reload the
* whole thing.
*/
this->lb_share_manager.invalidate_refs();
prefill = 0;
this->lb_buffer_size = 0;
if ((this->lb_file_size != (size_t)-1) &&
@ -284,6 +284,8 @@ throw (error)
* Need more space, move any existing data to the front of the
* buffer.
*/
this->lb_share_manager.invalidate_refs();
this->lb_buffer_size -= prefill;
this->lb_file_offset += prefill;
memmove(&this->lb_buffer[0],
@ -295,8 +297,6 @@ throw (error)
this->resize_buffer(this->lb_buffer_max +
DEFAULT_LINE_BUFFER_SIZE);
}
this->lb_share_manager.invalidate_refs();
}
}

View File

@ -110,6 +110,7 @@
#include "lnav_config.hh"
#include "sql_util.hh"
#include "sqlite-extension-func.h"
#include "sysclip.hh"
#include "term_extra.hh"
#include "log_data_helper.hh"
#include "readline_highlighters.hh"
@ -531,8 +532,28 @@ static void add_view_text_possibilities(
readline_curses *rlc = lnav_data.ld_rl_view;
rlc->clear_possibilities(context, type);
{
auto_mem<FILE> pfile(pclose);
pfile = open_clipboard(CT_FIND, CO_READ);
if (pfile.in() != NULL) {
char buffer[64];
if (fgets(buffer, sizeof(buffer), pfile) != NULL) {
char *nl;
buffer[sizeof(buffer) - 1] = '\0';
if ((nl = strchr(buffer, '\n')) != NULL) {
*nl = '\0';
}
rlc->add_possibility(context, type, std::string(buffer));
}
}
}
for (vis_line_t curr_line = tc->get_top();
curr_line < tc->get_bottom();
curr_line <= tc->get_bottom();
++curr_line) {
string line;
@ -1215,22 +1236,6 @@ static bool moveto_cluster(vis_line_t(bookmark_vector<vis_line_t>::*f) (
return false;
}
static void check_for_clipboard(FILE **pfile, const char *execstr)
{
if (execstr == NULL || pfile == NULL || *pfile != NULL) {
return;
}
if ((*pfile = popen(execstr, "w")) != NULL && pclose(*pfile) == 0) {
*pfile = popen(execstr, "w");
}
else {
*pfile = NULL;
}
return;
}
/* XXX For one, this code is kinda crappy. For two, we should probably link
* directly with X so we don't need to have xclip installed and it'll work if
* we're ssh'd into a box.
@ -1242,17 +1247,13 @@ static void copy_to_xclip(void)
bookmark_vector<vis_line_t> &bv =
tc->get_bookmarks()[&textview_curses::BM_USER];
bookmark_vector<vis_line_t>::iterator iter;
FILE * pfile = NULL;
auto_mem<FILE> pfile(pclose);
int line_count = 0;
string line;
/* XXX : Check if this is linux or MAC. Probably not the best solution but */
/* better than traversing the PATH to stat for the binaries or trying to */
/* forkexec. */
check_for_clipboard(&pfile, "xclip -i > /dev/null 2>&1");
check_for_clipboard(&pfile, "pbcopy > /dev/null 2>&1");
pfile = open_clipboard(CT_GENERAL);
if (!pfile) {
if (!pfile.in()) {
flash();
lnav_data.ld_rl_view->set_value(
"error: Unable to copy to clipboard. "
@ -1266,9 +1267,6 @@ static void copy_to_xclip(void)
line_count += 1;
}
pclose(pfile);
pfile = NULL;
char buffer[128];
snprintf(buffer, sizeof(buffer),
@ -2779,6 +2777,12 @@ static void rl_callback(void *dummy, readline_curses *rc)
case LNM_CAPTURE:
rl_search_internal(dummy, rc, true);
if (rc->get_value().size() > 0) {
auto_mem<FILE> pfile(pclose);
pfile = open_clipboard(CT_FIND);
if (pfile.in() != NULL) {
fprintf(pfile, "%s", rc->get_value().c_str());
}
lnav_data.ld_view_stack.top()->set_follow_search(false);
rc->set_value("search: " + rc->get_value());
rc->set_alt_value(HELP_MSG_2(
@ -2864,7 +2868,7 @@ static void rl_display_next(void *dummy, readline_curses *rc)
static void usage(void)
{
const char *usage_msg =
"usage: %s [-hVsar] [logfile1 logfile2 ...]\n"
"usage: %s [options] [logfile1 logfile2 ...]\n"
"\n"
"A curses-based log file viewer that indexes log messages by type\n"
"and time to make it easier to navigate through files quickly.\n"
@ -2901,7 +2905,7 @@ static void usage(void)
"\n"
"Examples:\n"
" To load and follow the syslog file:\n"
" $ lnav -s\n"
" $ lnav\n"
"\n"
" To load all of the files in /var/log:\n"
" $ lnav /var/log\n"

80
src/sysclip.cc Normal file
View File

@ -0,0 +1,80 @@
/**
* Copyright (c) 2014, Timothy Stack
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* * Neither the name of Timothy Stack nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ''AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* @file sysclip.cc
*/
#include "config.h"
#include <stdio.h>
#include "lnav_log.hh"
#include "sysclip.hh"
struct clip_command {
const char *cc_cmd[2];
};
static clip_command *get_commands()
{
static clip_command OSX_CMDS[] = {
{ { "pbcopy > /dev/null 2>&1",
"pbpaste -Prefer txt 2>/dev/null", } },
{ { "pbcopy -pboard find > /dev/null 2>&1",
"pbpaste -pboard find -Prefer txt 2>/dev/null" } },
};
static clip_command X_CMDS[] = {
{ { "xclip -i > /dev/null 2>&1",
"xclip -o < /dev/null 2>/dev/null" } },
{ { NULL, NULL } },
};
if (system("which pbcopy > /dev/null 2>&1") == 0) {
return OSX_CMDS;
}
if (system("which xclip > /dev/null 2>&1") == 0) {
return X_CMDS;
}
return NULL;
}
/* XXX For one, this code is kinda crappy. For two, we should probably link
* directly with X so we don't need to have xclip installed and it'll work if
* we're ssh'd into a box.
*/
FILE *open_clipboard(clip_type_t type, clip_op_t op)
{
const char *mode = op == CO_WRITE ? "w" : "r";
clip_command *cc = get_commands();
FILE *pfile = NULL;
if (cc != NULL) {
pfile = popen(cc[type].cc_cmd[op], mode);
}
return pfile;
}

47
src/sysclip.hh Normal file
View File

@ -0,0 +1,47 @@
/**
* Copyright (c) 2014, Timothy Stack
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* * Neither the name of Timothy Stack nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ''AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* @file sysclip.hh
*/
#ifndef __sysclip_hh
#define __sysclip_hh
enum clip_type_t {
CT_GENERAL,
CT_FIND,
};
enum clip_op_t {
CO_WRITE,
CO_READ,
};
FILE *open_clipboard(clip_type_t type, clip_op_t op = CO_WRITE);
#endif