Added the possibility of contextual help on user functions.

Добавлена возможность просмотра скриптов создания пользовательских объектов
в контестной помощи. В скриптах имена других объектов заменяются на ссылки.
Описание Readme.md
This commit is contained in:
lsv 2025-11-21 16:23:26 +05:00
parent 560bf4c080
commit 1f7decd73f
18 changed files with 1016 additions and 159 deletions

View file

@ -77,6 +77,7 @@ namespace FSQL {
{ "left", 4, new_line_align_next },
{ "full", 4, new_line_align_next },
{ "then", 4, none},
{ "loop", 4, none}, // for plpgsql
{ "into", 4, none},
{ "last", 4, none},
{ "next", 4, none},
@ -86,6 +87,9 @@ namespace FSQL {
{ "sets", 4, none},
{ "where", 5, new_line_align_no_pad | end_from},
{ "outer", 5, none},
{ "grant", 5, none},
{ "begin", 5, none}, //plpgsql
{ "while", 5, none}, //plpgsql
{ "union", 5, new_line_align_no_pad | end_from},
{ "order", 5, new_line_align_no_pad | end_from},
{ "limit", 5, new_line_align_no_pad | end_from},
@ -106,9 +110,11 @@ namespace FSQL {
{ "except", 6, new_line_align_no_pad | end_from},
{ "offset", 6, none | end_from},
{ "cursor", 6, none},
{ "create", 6, none},
{ "nothing", 7, none},
{ "lateral", 7, none},
{ "between", 7, none},
{ "comment", 7, none},
{ "nothing", 7, none},
{ "default", 7, none},
@ -149,11 +155,13 @@ namespace FSQL {
FormatterSQL(const wxString& sqlsrc) {
sql = sqlsrc;
}
std::vector<complite_element> ParsePLpgsql();
void Formating(wxDC& d, wxRect re, bool isTest = false); // draw
wxString Formating(wxRect re); //
//
wxString BuildAutoComplite(int startIndex, int level);
wxString GetListTable(int cursorPos);
wxString GetListTable(const std::vector<complite_element> &list);
wxString GetColsList(wxString what, wxString& listfieldOut, wxString& nameTableOut);
/// <summary>
/// Возращает количество таблиц слева от курсора и заполняет их имена и псевдонимы.
@ -166,11 +174,13 @@ namespace FSQL {
void SetSql(const wxString& sqlsrc) { sql = sqlsrc; lastposition = 0; }
int GetIndexItemNextSqlPosition(int sqlPosition);
int GetNextPositionSqlParse();
bool GetItem(int index, FSQL::view_item& item);
int next_item_no_space(int& index, int direction = 1);
private:
wxString get_list_columns(int startindex, union FSQL::Byte zone);
void _addfunc(const view_item *vi);
void _addfunc_in_braket(int start,int end);
wxPoint align_level(int start_i, int level, int Xpos, int Ypos, int flag);
int check_bracket(int index);
int get_prev_value(int indx, wxString keyword);
@ -185,8 +195,10 @@ namespace FSQL {
wxRect rect;
wxString sql;
int lastposition = 0;
int errorposition=-1;
std::vector<FSQL::view_item> items;
std::vector<FSQL::complite_element> listTable; // перечень таблиц синонимов, подзапросов и функций с колонками
std::vector<FSQL::complite_element> listFunction; // перечень функций используемых в запросе
//int recurse(int level);
};
}

View file

@ -5,16 +5,11 @@
#include <wx/regex.h>
#include <map>
#include <vector>
#include <wx/stdpaths.h>
#include <wx/textfile.h>
#include <wx/filename.h>
extern sysSettings* settings;
class FunctionPGHelper
{
public:
FunctionPGHelper() {};
FunctionPGHelper() {dblast=NULL;};
/// <summary>
/// Создать только переданный в конструкторе html текст с именем "content"
/// </summary>
@ -23,6 +18,7 @@ public:
body.clear();
Add("content", content);
isload = true;
dblast=NULL;
};
int Size() {
return body.size();
@ -30,126 +26,23 @@ public:
void SetTimerClose(int ms) { m_interval = ms; }
int GetTimerClose() { return m_interval; }
void Add(const wxString& key, const wxString& v) { body.emplace(key, v); }
wxString getHelpString(wxString fnd, bool isPart = true) {
if (!isValid()) return wxEmptyString;
auto search = body.find(fnd);
wxString txt;
if (search != body.end())
txt = search->second;
else
{
std::vector<wxString> list;
int l = fnd.Len();
wxString b;
for (const auto& e : body) {
if (e.first.Len() > l && e.first.StartsWith(fnd)) {
list.push_back(e.first);
b = e.second;
}
}
if (list.size() == 1) txt = b;
else {
for (const auto& s : list) {
txt += wxString::Format("<a href=\"%s\">%s</a><br>", s, s);
}
}
}
//if (i == wxNOT_FOUND) return wxEmptyString;
return txt;
}
wxString getSqlCommandHelp(wxString fnd) {
wxUniChar sep = wxFileName::GetPathSeparator();
fnd.Replace(" ", "");
wxString f = wxFindFirstFile(path + sep + "sql-" + fnd + "*.html");
wxString last, txt;
int c = 0;
while (!f.empty())
{
f = f.AfterLast(sep);
last = f;
txt += wxString::Format("<a href=\"%s\">%s</a><br>", f, f);
f = wxFindNextFile();
c++;
}
if (last.empty()) {
return wxEmptyString;
}
else if (c == 1) {
return getHelpFile(last);
}
else {
return txt;
}
}
wxString getHelpFile(wxString filename) {
wxString tempDir = path + wxFileName::GetPathSeparator() + filename;
if (!wxFileExists(tempDir)) return wxEmptyString;
wxTextFile tfile;
tfile.Open(tempDir);
// read the first line
wxString str, sbody;
sbody = tfile.GetFirstLine();
bool flag = true;
wxRegEx b("(<body .*?>)");
while (!tfile.Eof())
{
str = tfile.GetNextLine();
if (flag && b.Matches(str)) {
size_t start, len;
b.GetMatch(&start, &len, 0);
str = str.Mid(start + len);
sbody = "<body>";
flag = false;
}
sbody += str;
}
return sbody;
}
bool isValid() {
if (!isload) loadfile();
return isload;
}
wxString getHelpString(wxString fnd, bool isPart = true) ;
wxString getHelpFile(wxString filename);
wxString getSqlCommandHelp(wxString fnd);
bool isValid();
void setDbConn(pgConn *db);
// Ищем ключевое слово в объектах БД
wxString getDBinfoKeyword(wxString objname,bool islower);
// Ищем файлы справки для команд sql
private:
bool isload = false;
int m_interval = -1;
wxString path;
std::map<wxString, wxString> body;
void loadfile() {
if (isload) return;
body.clear();
path = settings->GetPgHelpPath();
wxString tempDir = path + "_func.txt";
//tempDir="C:\\Users\\lsv\\Source\\Repos\\wxHtmlhint\\1";
if (!wxFileExists(tempDir)) return;
wxTextFile tfile;
tfile.Open(tempDir);
// read the first line
wxString str, sbody;
wxString name = tfile.GetFirstLine();
//wxSortedArrayString names;
name = name.AfterFirst('#');
// read all lines one by one
// until the end of the file
while (!tfile.Eof())
{
str = tfile.GetNextLine();
if (str.Left(1) == '#') {
body.emplace(name, sbody);
sbody = "";
name = str.AfterFirst('#');
}
else sbody += str;
}
body.emplace(name, sbody);
isload = true;
};
// db connect
pgConn *dblast;
void loadfile();
};
#endif

View file

@ -279,5 +279,7 @@ wxString commandLineCleanOption(const wxString &option, bool schemaObject = fals
wxString qtIdent(const wxString &value); // add " if necessary
wxString qtTypeIdent(const wxString &value); // add " if necessary
bool make_identifier(const wxString &strname, wxString &s, wxString &n, bool islower);
#endif

View file

@ -60,13 +60,17 @@ public:
htmlWindow->SetRelatedStatusBar(0);
//htmlWindow->SetPage("<html><body><h1>TEST</h1><span fgcolor=\"#332233\">Set Page Works</span></body></hmtl>");
wxString txt = hhelper->getHelpString(keyword);
wxString txt;
txt=hhelper->getDBinfoKeyword(keyword,true);
if (txt.IsEmpty()) {
txt = hhelper->getSqlCommandHelp(keyword);
txt = hhelper->getHelpString(keyword.Lower());
if (txt.empty()) {
isvalid = false;
return;
txt = hhelper->getSqlCommandHelp(keyword.Lower());
if (txt.empty()) {
isvalid = false;
return;
}
}
}
SetPage(txt);
@ -131,9 +135,13 @@ public:
this->Bind(wxEVT_HTML_LINK_CLICKED, [&](wxHtmlLinkEvent& event) {
wxHtmlLinkInfo i = event.GetLinkInfo();
wxString name = i.GetHref();
wxString body=this->hhelper->getHelpString(name);
wxString body;
body=this->hhelper->getDBinfoKeyword(name,false);
if (body.IsEmpty()) {
body = this->hhelper->getHelpFile(name);
body=this->hhelper->getHelpString(name);
if (body.IsEmpty()) {
body = this->hhelper->getHelpFile(name);
}
}
SetPage(body);
//ctext=htmlWindow->SelectionToText();
@ -153,12 +161,15 @@ public:
//wxString body = this->hhelper->getHelpString(name);
wxString ctext = htmlWindow->SelectionToText();
if (!ctext.IsEmpty()) {
wxClipboardLocker clip;
if (!clip ||
!wxTheClipboard->AddData(new wxTextDataObject(ctext)))
if (wxTheClipboard->Open())
{
wxDataObjectComposite* dataobj = new wxDataObjectComposite();
dataobj->Add(new wxTextDataObject(ctext));
//dataobj->Add(new wxHTMLDataObject(str));
wxTheClipboard->SetData(dataobj);
wxTheClipboard->Close();
}
wxString wname = GetParent()->GetName();
if (wname == "frmStatus") {
//CMD_EVENT_FIND_STR
@ -203,6 +214,7 @@ private:
wxSize sizew;
FunctionPGHelper* hhelper;
std::vector<wxString> hist;
std::vector<wxPoint> hist_viewp;
void SetPage(wxString innerbody,bool gethistory=false) {
wxString h;
int p = innerbody.Find("<body>");
@ -224,9 +236,22 @@ private:
h = hist[hist.size()-1];
}
else {
if (hist.size()>0) {
wxPoint ps=htmlWindow->GetViewStart();
hist_viewp.push_back(ps);
}
hist.push_back(h);
}
htmlWindow->SetPage(h);
if (gethistory && hist_viewp.size()>0) {
wxPoint ps=hist_viewp[hist_viewp.size()-1];
hist_viewp.pop_back();
htmlWindow->Scroll(ps);
} else {
//
wxPoint ps(0,0);
htmlWindow->Scroll(ps);
}
}
private:
wxTimer *closeTimer=NULL;