mirror of https://github.com/tstack/lnav
[sql] do some minimal parsing/annotation of SQL statements
Defect Number: Reviewed By: Testing Done:pull/111/merge
parent
0b157ff867
commit
8776f6a703
@ -0,0 +1,423 @@
|
||||
/**
|
||||
* Copyright (c) 2017, 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 attr_line.hh
|
||||
*/
|
||||
|
||||
#ifndef __attr_line_hh
|
||||
#define __attr_line_hh
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
/**
|
||||
* Encapsulates a range in a string.
|
||||
*/
|
||||
struct line_range {
|
||||
int lr_start;
|
||||
int lr_end;
|
||||
|
||||
explicit line_range(int start = -1, int end = -1) : lr_start(start), lr_end(end) { };
|
||||
|
||||
bool is_valid() const {
|
||||
return this->lr_start != -1;
|
||||
}
|
||||
|
||||
int length() const
|
||||
{
|
||||
return this->lr_end == -1 ? INT_MAX : this->lr_end - this->lr_start;
|
||||
};
|
||||
|
||||
bool contains(int pos) const {
|
||||
return this->lr_start <= pos && pos < this->lr_end;
|
||||
};
|
||||
|
||||
bool contains(const struct line_range &other) const {
|
||||
return this->contains(other.lr_start) && other.lr_end <= this->lr_end;
|
||||
};
|
||||
|
||||
bool intersects(const struct line_range &other) const {
|
||||
return this->contains(other.lr_start) || this->contains(other.lr_end);
|
||||
};
|
||||
|
||||
line_range intersection(const struct line_range &other) const {
|
||||
return line_range{std::max(this->lr_start, other.lr_start),
|
||||
std::min(this->lr_end, other.lr_end)};
|
||||
};
|
||||
|
||||
line_range &shift(int32_t start, int32_t amount) {
|
||||
if (this->lr_start >= start) {
|
||||
this->lr_start = std::max(0, this->lr_start + amount);
|
||||
}
|
||||
if (this->lr_end != -1 && start < this->lr_end) {
|
||||
this->lr_end += amount;
|
||||
if (this->lr_end < this->lr_start) {
|
||||
this->lr_end = this->lr_start;
|
||||
}
|
||||
}
|
||||
|
||||
return *this;
|
||||
};
|
||||
|
||||
void ltrim(const char *str) {
|
||||
while (this->lr_start < this->lr_end && isspace(str[this->lr_start])) {
|
||||
this->lr_start += 1;
|
||||
}
|
||||
};
|
||||
|
||||
bool operator<(const struct line_range &rhs) const
|
||||
{
|
||||
if (this->lr_start < rhs.lr_start) { return true; }
|
||||
else if (this->lr_start > rhs.lr_start) { return false; }
|
||||
|
||||
if (this->lr_end == rhs.lr_end) { return false; }
|
||||
|
||||
if (this->lr_end < rhs.lr_end) { return true; }
|
||||
return false;
|
||||
};
|
||||
|
||||
bool operator==(const struct line_range &rhs) const {
|
||||
return (this->lr_start == rhs.lr_start && this->lr_end == rhs.lr_end);
|
||||
};
|
||||
|
||||
const char *substr(const std::string &str) const {
|
||||
if (this->lr_start == -1) {
|
||||
return str.c_str();
|
||||
}
|
||||
return &(str.c_str()[this->lr_start]);
|
||||
}
|
||||
|
||||
size_t sublen(const std::string &str) const {
|
||||
if (this->lr_start == -1) {
|
||||
return str.length();
|
||||
}
|
||||
if (this->lr_end == -1) {
|
||||
return str.length() - this->lr_start;
|
||||
}
|
||||
return this->length();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Container for attribute values for a substring.
|
||||
*/
|
||||
typedef union {
|
||||
void *sav_ptr;
|
||||
int64_t sav_int;
|
||||
} string_attr_value_t;
|
||||
|
||||
class string_attr_type {
|
||||
public:
|
||||
string_attr_type(const char *name = nullptr)
|
||||
: sat_name(name) {
|
||||
};
|
||||
|
||||
const char *sat_name;
|
||||
};
|
||||
typedef string_attr_type *string_attr_type_t;
|
||||
|
||||
struct string_attr {
|
||||
string_attr(const struct line_range &lr, string_attr_type_t type, void *val)
|
||||
: sa_range(lr), sa_type(type) {
|
||||
this->sa_value.sav_ptr = val;
|
||||
};
|
||||
|
||||
string_attr(const struct line_range &lr, string_attr_type_t type, int64_t val = 0)
|
||||
: sa_range(lr), sa_type(type) {
|
||||
this->sa_value.sav_int = val;
|
||||
};
|
||||
|
||||
string_attr(const struct line_range &lr, string_attr_type_t type, string_attr_value_t val)
|
||||
: sa_range(lr), sa_type(type), sa_value(val) {
|
||||
};
|
||||
|
||||
string_attr() : sa_type(NULL) { };
|
||||
|
||||
bool operator<(const struct string_attr &rhs) const
|
||||
{
|
||||
return this->sa_range < rhs.sa_range;
|
||||
};
|
||||
|
||||
struct line_range sa_range;
|
||||
string_attr_type_t sa_type;
|
||||
string_attr_value_t sa_value;
|
||||
};
|
||||
|
||||
/** A map of line ranges to attributes for that range. */
|
||||
typedef std::vector<string_attr> string_attrs_t;
|
||||
|
||||
inline string_attrs_t::const_iterator
|
||||
find_string_attr(const string_attrs_t &sa, string_attr_type_t type, int start = 0)
|
||||
{
|
||||
string_attrs_t::const_iterator iter;
|
||||
|
||||
for (iter = sa.begin(); iter != sa.end(); ++iter) {
|
||||
if (iter->sa_type == type && iter->sa_range.lr_start >= start) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return iter;
|
||||
}
|
||||
|
||||
inline string_attrs_t::iterator
|
||||
find_string_attr(string_attrs_t &sa, const struct line_range &lr)
|
||||
{
|
||||
string_attrs_t::iterator iter;
|
||||
|
||||
for (iter = sa.begin(); iter != sa.end(); ++iter) {
|
||||
if (lr.contains(iter->sa_range)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return iter;
|
||||
}
|
||||
|
||||
inline string_attrs_t::const_iterator
|
||||
find_string_attr(const string_attrs_t &sa, size_t near)
|
||||
{
|
||||
string_attrs_t::const_iterator iter, nearest = sa.end();
|
||||
ssize_t last_diff = INT_MAX;
|
||||
|
||||
for (iter = sa.begin(); iter != sa.end(); ++iter) {
|
||||
auto &lr = iter->sa_range;
|
||||
|
||||
if (!lr.is_valid() || !lr.contains(near)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ssize_t diff = near - lr.lr_start;
|
||||
if (diff < last_diff) {
|
||||
last_diff = diff;
|
||||
nearest = iter;
|
||||
}
|
||||
}
|
||||
|
||||
return nearest;
|
||||
}
|
||||
|
||||
inline struct line_range
|
||||
find_string_attr_range(const string_attrs_t &sa, string_attr_type_t type)
|
||||
{
|
||||
string_attrs_t::const_iterator iter = find_string_attr(sa, type);
|
||||
|
||||
if (iter != sa.end()) {
|
||||
return iter->sa_range;
|
||||
}
|
||||
|
||||
return line_range();
|
||||
}
|
||||
|
||||
inline void remove_string_attr(string_attrs_t &sa, const struct line_range &lr)
|
||||
{
|
||||
string_attrs_t::iterator iter;
|
||||
|
||||
while ((iter = find_string_attr(sa, lr)) != sa.end()) {
|
||||
sa.erase(iter);
|
||||
}
|
||||
}
|
||||
|
||||
inline void remove_string_attr(string_attrs_t &sa, string_attr_type_t type)
|
||||
{
|
||||
string_attrs_t::iterator iter;
|
||||
|
||||
for (auto iter = sa.begin(); iter != sa.end();) {
|
||||
if (iter->sa_type == type) {
|
||||
iter = sa.erase(iter);
|
||||
} else {
|
||||
++iter;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline void shift_string_attrs(string_attrs_t &sa, int32_t start, int32_t amount)
|
||||
{
|
||||
for (string_attrs_t::iterator iter = sa.begin(); iter != sa.end(); ++iter) {
|
||||
iter->sa_range.shift(start, amount);
|
||||
}
|
||||
}
|
||||
|
||||
struct text_wrap_settings {
|
||||
text_wrap_settings() : tws_indent(2), tws_width(80) {};
|
||||
|
||||
text_wrap_settings &with_indent(int indent) {
|
||||
this->tws_indent = indent;
|
||||
return *this;
|
||||
};
|
||||
|
||||
text_wrap_settings &with_width(int width) {
|
||||
this->tws_width = width;
|
||||
return *this;
|
||||
};
|
||||
|
||||
int tws_indent;
|
||||
int tws_width;
|
||||
};
|
||||
|
||||
/**
|
||||
* A line that has attributes.
|
||||
*/
|
||||
class attr_line_t {
|
||||
public:
|
||||
attr_line_t() {
|
||||
this->al_attrs.reserve(RESERVE_SIZE);
|
||||
};
|
||||
|
||||
attr_line_t(const std::string &str) : al_string(str) {
|
||||
this->al_attrs.reserve(RESERVE_SIZE);
|
||||
};
|
||||
|
||||
attr_line_t(const char *str) : al_string(str) {
|
||||
this->al_attrs.reserve(RESERVE_SIZE);
|
||||
};
|
||||
|
||||
static inline attr_line_t from_ansi_str(const char *str) {
|
||||
attr_line_t retval;
|
||||
|
||||
return retval.with_ansi_string(str);
|
||||
};
|
||||
|
||||
/** @return The string itself. */
|
||||
std::string &get_string() { return this->al_string; };
|
||||
|
||||
/** @return The attributes for the string. */
|
||||
string_attrs_t &get_attrs() { return this->al_attrs; };
|
||||
|
||||
attr_line_t &with_string(const std::string &str) {
|
||||
this->al_string = str;
|
||||
return *this;
|
||||
}
|
||||
|
||||
attr_line_t &with_ansi_string(const char *str, ...);
|
||||
|
||||
attr_line_t &with_attr(const string_attr &sa) {
|
||||
this->al_attrs.push_back(sa);
|
||||
return *this;
|
||||
};
|
||||
|
||||
template<typename T = void *>
|
||||
attr_line_t &append(const char *str,
|
||||
string_attr_type_t type = nullptr,
|
||||
T val = T()) {
|
||||
size_t start_len = this->al_string.length();
|
||||
|
||||
this->al_string.append(str);
|
||||
if (type != nullptr) {
|
||||
line_range lr{(int) start_len, (int) this->al_string.length()};
|
||||
|
||||
this->al_attrs.emplace_back(lr, type, val);
|
||||
}
|
||||
return *this;
|
||||
};
|
||||
|
||||
attr_line_t &append(const attr_line_t &al, text_wrap_settings *tws = nullptr);
|
||||
|
||||
attr_line_t &append(size_t len, char c) {
|
||||
this->al_string.append(len, c);
|
||||
return *this;
|
||||
};
|
||||
|
||||
attr_line_t &insert(size_t index, size_t len, char c) {
|
||||
this->al_string.insert(index, len, c);
|
||||
|
||||
shift_string_attrs(this->al_attrs, index, len);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
attr_line_t &insert(size_t index, const char *str) {
|
||||
this->al_string.insert(index, str);
|
||||
|
||||
shift_string_attrs(this->al_attrs, index, strlen(str));
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
attr_line_t &right_justify(unsigned long width) {
|
||||
long padding = width - this->length();
|
||||
if (padding > 0) {
|
||||
this->al_string.insert(0, padding, ' ');
|
||||
for (std::vector<string_attr>::iterator iter = this->al_attrs.begin();
|
||||
iter != this->al_attrs.end();
|
||||
++iter) {
|
||||
iter->sa_range.lr_start += padding;
|
||||
iter->sa_range.lr_end += padding;
|
||||
}
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
ssize_t length() const {
|
||||
size_t retval = this->al_string.length();
|
||||
|
||||
for (std::vector<string_attr>::const_iterator iter = this->al_attrs.begin();
|
||||
iter != this->al_attrs.end();
|
||||
++iter) {
|
||||
retval = std::max(retval, (size_t) iter->sa_range.lr_start);
|
||||
if (iter->sa_range.lr_end != -1) {
|
||||
retval = std::max(retval, (size_t) iter->sa_range.lr_end);
|
||||
}
|
||||
}
|
||||
|
||||
return retval;
|
||||
};
|
||||
|
||||
std::string get_substring(const line_range &lr) const {
|
||||
if (!lr.is_valid()) {
|
||||
return "";
|
||||
}
|
||||
return this->al_string.substr(lr.lr_start, lr.length());
|
||||
};
|
||||
|
||||
bool empty() const {
|
||||
return this->length() == 0;
|
||||
};
|
||||
|
||||
/** Clear the string and the attributes for the string. */
|
||||
attr_line_t &clear()
|
||||
{
|
||||
this->al_string.clear();
|
||||
this->al_attrs.clear();
|
||||
|
||||
return *this;
|
||||
};
|
||||
|
||||
attr_line_t subline(size_t start, size_t len = std::string::npos) const;
|
||||
|
||||
void split_lines(std::vector<attr_line_t> &lines) const;
|
||||
|
||||
private:
|
||||
const static size_t RESERVE_SIZE = 128;
|
||||
|
||||
std::string al_string;
|
||||
string_attrs_t al_attrs;
|
||||
};
|
||||
|
||||
#endif
|
@ -0,0 +1,70 @@
|
||||
/**
|
||||
* Copyright (c) 2017, 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.
|
||||
*/
|
||||
|
||||
#ifndef _doc_status_source_hh
|
||||
#define _doc_status_source_hh
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "lnav_config.hh"
|
||||
#include "logfile_sub_source.hh"
|
||||
#include "statusview_curses.hh"
|
||||
|
||||
class doc_status_source
|
||||
: public status_data_source {
|
||||
public:
|
||||
typedef enum {
|
||||
TSF_TITLE,
|
||||
TSF_STITCH_TITLE,
|
||||
|
||||
TSF__MAX
|
||||
} field_t;
|
||||
|
||||
doc_status_source()
|
||||
{
|
||||
this->tss_fields[TSF_TITLE].set_width(14);
|
||||
this->tss_fields[TSF_TITLE].set_role(view_colors::VCR_VIEW_STATUS);
|
||||
this->tss_fields[TSF_TITLE].set_value(" Command Help ");
|
||||
this->tss_fields[TSF_STITCH_TITLE].set_width(2);
|
||||
this->tss_fields[TSF_STITCH_TITLE].set_stitch_value(
|
||||
view_colors::ansi_color_pair_index(COLOR_BLUE, COLOR_WHITE));
|
||||
};
|
||||
|
||||
size_t statusview_fields(void) { return TSF__MAX; };
|
||||
|
||||
status_field &statusview_value_for_field(int field)
|
||||
{
|
||||
return this->tss_fields[field];
|
||||
};
|
||||
|
||||
private:
|
||||
status_field tss_fields[TSF__MAX];
|
||||
};
|
||||
|
||||
#endif
|
@ -0,0 +1,147 @@
|
||||
/**
|
||||
* Copyright (c) 2017, 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.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <numeric>
|
||||
#include <algorithm>
|
||||
|
||||
#include "ansi_scrubber.hh"
|
||||
#include "help_text_formatter.hh"
|
||||
#include "readline_highlighters.hh"
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
||||
void format_help_text_for_term(const help_text &ht, int width, attr_line_t &out)
|
||||
{
|
||||
static size_t body_indent = 2;
|
||||
|
||||
text_wrap_settings tws;
|
||||
|
||||
tws.with_width(width);
|
||||
|
||||
switch (ht.ht_context) {
|
||||
case HC_COMMAND: {
|
||||
out.append("Synopsis", &view_curses::VC_STYLE, A_UNDERLINE)
|
||||
.append("\n")
|
||||
.append(body_indent, ' ')
|
||||
.append(":")
|
||||
.append(ht.ht_name, &view_curses::VC_STYLE, A_BOLD);
|
||||
for (auto ¶m : ht.ht_parameters) {
|
||||
out.append(" ");
|
||||
out.append(param.ht_name, &view_curses::VC_STYLE, A_UNDERLINE);
|
||||
if (param.ht_nargs == HN_ONE_OR_MORE) {
|
||||
out.append("1", &view_curses::VC_STYLE, A_UNDERLINE);
|
||||
out.append(" [");
|
||||
out.append("...", &view_curses::VC_STYLE, A_UNDERLINE);
|
||||
out.append(" ");
|
||||
out.append(param.ht_name, &view_curses::VC_STYLE, A_UNDERLINE);
|
||||
out.append("N", &view_curses::VC_STYLE, A_UNDERLINE);
|
||||
out.append("]");
|
||||
}
|
||||
}
|
||||
out.append(" - ")
|
||||
.append(attr_line_t::from_ansi_str(ht.ht_summary),
|
||||
&tws.with_indent(body_indent + 4))
|
||||
.append("\n");
|
||||
break;
|
||||
}
|
||||
case HC_SQL_FUNCTION: {
|
||||
bool needs_comma = false;
|
||||
|
||||
out.append(ht.ht_name, &view_curses::VC_STYLE, A_BOLD);
|
||||
out.append("(");
|
||||
for (auto ¶m : ht.ht_parameters) {
|
||||
if (needs_comma) {
|
||||
out.append(", ");
|
||||
}
|
||||
out.append(param.ht_name, &view_curses::VC_STYLE, A_UNDERLINE);
|
||||
needs_comma = true;
|
||||
}
|
||||
out.append(") -- ")
|
||||
.append(attr_line_t::from_ansi_str(ht.ht_summary), &tws)
|
||||
.append("\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!ht.ht_parameters.empty()) {
|
||||
size_t max_param_name_width = 0;
|
||||
|
||||
for (auto ¶m : ht.ht_parameters) {
|
||||
max_param_name_width = std::max(strlen(param.ht_name), max_param_name_width);
|
||||
}
|
||||
|
||||
out.append(ht.ht_parameters.size() == 1 ? "Parameter" : "Parameters",
|
||||
&view_curses::VC_STYLE,
|
||||
A_UNDERLINE)
|
||||
.append("\n");
|
||||
|
||||
for (auto ¶m : ht.ht_parameters) {
|
||||
out.append(body_indent, ' ')
|
||||
.append(param.ht_name,
|
||||
&view_curses::VC_STYLE,
|
||||
view_colors::ansi_color_pair(COLOR_CYAN, COLOR_BLACK) | A_BOLD)
|
||||
.append(max_param_name_width - strlen(param.ht_name), ' ')
|
||||
.append(" ")
|
||||
.append(attr_line_t::from_ansi_str(param.ht_summary),
|
||||
&(tws.with_indent(2 + max_param_name_width + 3)))
|
||||
.append("\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (!ht.ht_example.empty()) {
|
||||
map<string, string> vars;
|
||||
|
||||
vars["name"] = ht.ht_name;
|
||||
add_ansi_vars(vars);
|
||||
|
||||
out.append(ht.ht_example.size() == 1 ? "Example" : "Examples",
|
||||
&view_curses::VC_STYLE,
|
||||
A_UNDERLINE)
|
||||
.append("\n");
|
||||
for (auto &ex : ht.ht_example) {
|
||||
attr_line_t ex_line(ex.he_cmd);
|
||||
|
||||
switch (ht.ht_context) {
|
||||
case HC_COMMAND:
|
||||
ex_line.insert(0, 1, ' ');
|
||||
ex_line.insert(0, 1, ':');
|
||||
ex_line.insert(1, ht.ht_name);
|
||||
readline_command_highlighter(ex_line, 0);
|
||||
break;
|
||||
}
|
||||
|
||||
out.append(body_indent, ' ')
|
||||
.append(ex_line, &tws.with_indent(body_indent + 2));
|
||||
out.append("\n");
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,156 @@
|
||||
/**
|
||||
* Copyright (c) 2017, 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.
|
||||
*/
|
||||
|
||||
#ifndef LNAV_HELP_TEXT_FORMATTER_HH
|
||||
#define LNAV_HELP_TEXT_FORMATTER_HH
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "attr_line.hh"
|
||||
|
||||
enum help_context_t {
|
||||
HC_NONE,
|
||||
HC_PARAMETER,
|
||||
HC_COMMAND,
|
||||
HC_SQL_FUNCTION,
|
||||
};
|
||||
|
||||
enum help_nargs_t {
|
||||
HN_REQUIRED,
|
||||
HN_OPTIONAL,
|
||||
HN_ZERO_OR_MORE,
|
||||
HN_ONE_OR_MORE,
|
||||
};
|
||||
|
||||
enum help_parameter_format_t {
|
||||
HPF_STRING,
|
||||
HPF_REGEX,
|
||||
HPF_INTEGER,
|
||||
HPF_NUMBER,
|
||||
HPF_DATETIME,
|
||||
HPF_ENUM,
|
||||
};
|
||||
|
||||
struct help_example {
|
||||
const char *he_cmd;
|
||||
const char *he_result;
|
||||
};
|
||||
|
||||
struct help_text {
|
||||
help_context_t ht_context;
|
||||
const char *ht_name;
|
||||
const char *ht_summary;
|
||||
const char *ht_description;
|
||||
std::vector<struct help_text> ht_parameters;
|
||||
std::vector<struct help_example> ht_example;
|
||||
help_nargs_t ht_nargs;
|
||||
help_parameter_format_t ht_format;
|
||||
std::vector<const char *> ht_enum_values;
|
||||
|
||||
help_text() : ht_context(HC_NONE) {
|
||||
|
||||
};
|
||||
|
||||
help_text(const char *name, const char *summary = nullptr)
|
||||
: ht_context(HC_NONE),
|
||||
ht_name(name),
|
||||
ht_summary(summary),
|
||||
ht_description(nullptr),
|
||||
ht_nargs(HN_REQUIRED),
|
||||
ht_format(HPF_STRING) {
|
||||
if (name[0] == ':') {
|
||||
this->ht_context = HC_COMMAND;
|
||||
this->ht_name = &name[1];
|
||||
}
|
||||
}
|
||||
|
||||
help_text &command() {
|
||||
this->ht_context = HC_COMMAND;
|
||||
return *this;
|
||||
};
|
||||
|
||||
help_text &with_summary(const char *summary) {
|
||||
this->ht_summary = summary;
|
||||
return *this;
|
||||
};
|
||||
|
||||
help_text &with_parameters(const std::initializer_list<help_text> ¶ms) {
|
||||
this->ht_parameters = params;
|
||||
for (auto ¶m : this->ht_parameters) {
|
||||
param.ht_context = HC_PARAMETER;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
help_text &with_parameter(const help_text &ht) {
|
||||
this->ht_parameters.emplace_back(ht);
|
||||
this->ht_parameters.back().ht_context = HC_PARAMETER;
|
||||
return *this;
|
||||
};
|
||||
|
||||
help_text &with_examples(const std::initializer_list<help_example> &examples) {
|
||||
this->ht_example = examples;
|
||||
return *this;
|
||||
}
|
||||
|
||||
help_text &with_example(const help_example &example) {
|
||||
this->ht_example.emplace_back(example);
|
||||
return *this;
|
||||
}
|
||||
|
||||
help_text &optional() {
|
||||
this->ht_nargs = HN_OPTIONAL;
|
||||
return *this;
|
||||
};
|
||||
|
||||
help_text &zero_or_more() {
|
||||
this->ht_nargs = HN_ZERO_OR_MORE;
|
||||
return *this;
|
||||
};
|
||||
|
||||
help_text &one_or_more() {
|
||||
this->ht_nargs = HN_ONE_OR_MORE;
|
||||
return *this;
|
||||
};
|
||||
|
||||
help_text &with_format(help_parameter_format_t format) {
|
||||
this->ht_format = format;
|
||||
return *this;
|
||||
}
|
||||
|
||||
help_text &with_enum_values(const std::initializer_list<const char*> &enum_values) {
|
||||
this->ht_enum_values = enum_values;
|
||||
return *this;
|
||||
};
|
||||
};
|
||||
|
||||
void format_help_text_for_term(const help_text &ht, int width, attr_line_t &out);
|
||||
|
||||
#endif //LNAV_HELP_TEXT_FORMATTER_HH
|
@ -0,0 +1,76 @@
|
||||
/**
|
||||
* Copyright (c) 2017, 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 drive_sql_anno.cc
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
|
||||
#include "lnav.hh"
|
||||
#include "sql_util.hh"
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int retval = EXIT_SUCCESS;
|
||||
|
||||
log_argv(argc, argv);
|
||||
|
||||
if (argc < 2) {
|
||||
fprintf(stderr, "error: expecting an SQL statement\n");
|
||||
retval = EXIT_FAILURE;
|
||||
}
|
||||
else {
|
||||
attr_line_t al(argv[1]);
|
||||
|
||||
annotate_sql_statement(al);
|
||||
|
||||
for (auto &attr : al.get_attrs()) {
|
||||
auto &lr = attr.sa_range;
|
||||
|
||||
printf(" %d:%d (%s) -- %s\n",
|
||||
lr.lr_start, lr.lr_end,
|
||||
attr.sa_type->sat_name,
|
||||
al.get_substring(lr).c_str());
|
||||
}
|
||||
|
||||
if (argc == 3) {
|
||||
int near;
|
||||
sscanf(argv[2], "%d", &near);
|
||||
|
||||
auto iter = find_string_attr(al.get_attrs(), (size_t) near);
|
||||
if (iter != al.get_attrs().end()) {
|
||||
printf("nearest %s\n",
|
||||
al.get_substring(iter->sa_range).c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
@ -0,0 +1,87 @@
|
||||
/**
|
||||
* Copyright (c) 2017, 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.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <view_curses.hh>
|
||||
#include <attr_line.hh>
|
||||
|
||||
#include "lnav_config.hh"
|
||||
#include "help_text_formatter.hh"
|
||||
|
||||
struct _lnav_config lnav_config;
|
||||
|
||||
lnav_config_listener *lnav_config_listener::LISTENER_LIST;
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int retval = EXIT_SUCCESS;
|
||||
|
||||
static help_text ht = help_text(
|
||||
"regexp_replace",
|
||||
"Replace parts of a string that match a regular expression")
|
||||
.with_parameters(
|
||||
{
|
||||
{"str", "The string to perform replacements on"},
|
||||
{"re", "The regular expression to match"},
|
||||
{"repl", "The replacement string"},
|
||||
})
|
||||
.with_example(
|
||||
{
|
||||
";SELECT regexp_replace('abbb bbbc', 'b+', '') AS res",
|
||||
"a c",
|
||||
});
|
||||
|
||||
{
|
||||
setenv("TERM", "ansi", 1);
|
||||
screen_curses sc;
|
||||
view_colors::init();
|
||||
|
||||
attr_line_t al;
|
||||
|
||||
format_help_text_for_term(ht, 35, al);
|
||||
|
||||
std::vector<attr_line_t> lines;
|
||||
|
||||
al.split_lines(lines);
|
||||
|
||||
line_range lr{0, 80};
|
||||
|
||||
int y = 0;
|
||||
for (auto &line : lines) {
|
||||
view_curses::mvwattrline(sc.get_window(), y++, 0, line, lr);
|
||||
}
|
||||
|
||||
getch();
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
Loading…
Reference in New Issue