extended autocomplite

Add CallTipShow for function arguments,
Add autocomplite name fields
This commit is contained in:
levinsv 2018-12-09 22:06:14 +05:00
parent 1fe929a515
commit 28918bcc0a
6 changed files with 330 additions and 22 deletions

View file

@ -43,3 +43,6 @@ This text Russian language.
* В экспорте результатов запроса в Excel исправлена ошибка при сохранении интервалов
* При обновлении схемы не блокируется интерфейс если на таблице идет долгая операция cluster
Но при F5 на самой таблице блокировка сохраняется (это связано с блокированием функций pg_def* при получинии информации от таблицах)
09.12.2018
- autocomplite: добавлены имена функций, и возможность подставлять имена колонок таблиц из поля FROM
- при наборе имени функции появляется перечень параметров этой функции

Binary file not shown.

View file

@ -455,13 +455,106 @@ bool ctlSQLBox::DoFind(const wxString &find, const wxString &replace, bool doRep
void ctlSQLBox::SetAutoReplaceList(queryMacroList *autorep) {
autoreplace=autorep;
}
void ctlSQLBox::SetDefFunction(wxArrayString &name, wxArrayString &def) {
m_name=&name;
m_def=&def;
}
void ctlSQLBox::OnKeyDown(wxKeyEvent &event)
{
//wxString autoreplace[]={wxT("se"),wxT("select * from"),wxT("sc"),wxT("select count(*) from"),wxT("si"),wxT("select * from info_oper where"),wxT("sh"),wxT("select * from info_history where")};
#ifdef __WXGTK__
event.m_metaDown = false;
#endif
if (m_name)
{
if (((event.GetKeyCode() == '0')&&(event.GetModifiers() == (wxMOD_SHIFT)))
||event.GetKeyCode() == WXK_UP
||event.GetKeyCode() == WXK_DOWN)
{
if (CallTipActive()) CallTipCancel();
event.Skip();
return;
}
if ((event.GetKeyCode() == '9')&&(event.GetModifiers() == (wxMOD_SHIFT)))
{
int pos = GetCurrentPos() ;
//CallTipSetBackground(*wxYELLOW);
wxString line = GetLine(GetCurrentLine());
//int max = line.Length() - (GetLineEndPosition(GetCurrentLine()) - GetCurrentPos()) - offset;
int max= PositionFromLine(LineFromPosition(pos));
int l=0;
wxCharBuffer myStringChars = line.mb_str();
for (int kk=pos-max-1;kk>=0;kk--) {
//char c=myStringChars.data[kk];
if ( line[kk]<'0') break;
l++;
}
wxString f_name=GetTextRange(pos-l, pos);
int idx=m_name->Index(f_name,false,false);
if (idx!=wxNOT_FOUND) {
calltip=f_name +wxT("(")+m_def->Item(idx)+wxT(")");
ct_hl=calltip.Find(wxT(","));
if (ct_hl==wxNOT_FOUND) ct_hl=l;
for (int jj=idx+1;jj<m_name->Count();jj++) {
if (m_name->Item(jj)== f_name) {
calltip+=wxT("\n")+f_name +wxT("(")+m_def->Item(jj)+wxT(")");
} else break;
}
CallTipShow(pos-l,calltip);
CallTipSetHighlight(0,ct_hl);
}
//t = GetTextRange(pos-rpl.Length(), pos);
event.Skip();
return;
}
}
if (CallTipActive()&&(event.GetKeyCode() == ','
||event.GetKeyCode() == WXK_RIGHT
||event.GetKeyCode() == WXK_LEFT
)) {
//int ptip=CallTipPosAtStart();
int direction=1;
if (event.GetKeyCode() == WXK_LEFT)
direction=-1;
char c=GetCharAt(GetCurrentPos());
if (event.GetKeyCode() != ','&&c!=',' ) {
//direction=ct_hl;
} else
{
int pos=ct_hl+direction;
int a=0;
while ( (pos<calltip.Len())&&(pos>0)) {
c=calltip[pos];
if ((c==',')||(c=='\n')) {
if (direction==1) break;
if (a==1) break;
a++;
ct_hl=pos;
}
pos=pos+direction;
}
//int l=calltip.find(wxT(","),ct_hl+1);
int prev=ct_hl;
if (direction==-1) {
prev=pos;
pos=ct_hl;
} else
{
if (pos==wxNOT_FOUND||(pos==calltip.length())) pos=ct_hl;
}
CallTipSetHighlight(prev,pos);
ct_hl=pos;
}
}
// Get the line ending type
wxString lineEnd;
switch (GetEOLMode())
@ -485,7 +578,7 @@ void ctlSQLBox::OnKeyDown(wxKeyEvent &event)
//wxString line = GetLine(GetCurrentLine());
wxString t;
wxString wc;
char c;
//char c;
bool f;
wxString rpl = wxT("");
wxString rpl2 = wxT("");
@ -887,7 +980,7 @@ void ctlSQLBox::OnPositionStc(wxStyledTextEvent &event)
if ((ch == '{' || ch == '}' ||
ch == '[' || ch == ']' ||
ch == '(' || ch == ')') &&
st != 2 && st != 6 && st != 7)
st != 1 && st != 2 && st != 6 && st != 7)
{
match = BraceMatch(pos - 1);
if (match != wxSTC_INVALID_POSITION)
@ -896,32 +989,134 @@ void ctlSQLBox::OnPositionStc(wxStyledTextEvent &event)
else if ((nextch == '{' || nextch == '}' ||
nextch == '[' || nextch == ']' ||
nextch == '(' || nextch == ')') &&
st != 2 && st != 6 && st != 7)
st != 1 &&st != 2 && st != 6 && st != 7)
{
match = BraceMatch(pos);
if (match != wxSTC_INVALID_POSITION)
BraceHighlight(pos, match);
}
int startsql=0;
// Roll back through the doc and highlight any unmatched braces
int tmp=pos;
while ((pos--) >= 0)
{
ch = GetCharAt(pos);
st = GetStyleAt(pos);
if (st != 1 &&st != 2 && st != 6 && st != 7 &&(ch==';')&&startsql==0) startsql=pos+1;
if ((ch == '{' || ch == '}' ||
ch == '[' || ch == ']' ||
ch == '(' || ch == ')') &&
st != 2 && st != 6 && st != 7)
st != 1 &&st != 2 && st != 6 && st != 7)
{
match = BraceMatch(pos);
if (match == wxSTC_INVALID_POSITION)
{
BraceBadLight(pos);
break;
} else
{
}
}
}
// ïîëó÷åíèå ïîçèöè select
pos=tmp;
wxString keyword;
wxString ident;
while ((pos--) >= 0)
{
ch = GetCharAt(pos);
st = GetStyleAt(pos);
if (st==5) {ident.append(ch);} else
{
if ((!ident.IsEmpty())) {
if (ident.CmpNoCase(wxT("tceles"))==0) {
startsql=pos+1;
break;
}
ident.Clear();
}
}
if (st != 1 &&st != 2 && st != 6 && st != 7 &&(ch==';')&&startsql==0) startsql=pos+1;
if (( ch == '}' ||
ch == ']' ||
ch == ')') &&
st != 1 &&st != 2 && st != 6 && st != 7)
{
match = BraceMatch(pos);
if (match == wxSTC_INVALID_POSITION)
{
break;
} else
{
pos=match-1;
}
}
}
int endtext= GetLength();
bool isfrom=false;
pos=startsql;
list_table.Clear();
ident.Clear();
while (pos<endtext) {
ch = GetCharAt(pos);
st = GetStyleAt(pos);
if (st != 1 &&st != 2 && st != 6 && st != 7 &&((ch=='\r')||(ch=='\n'))) {pos++; continue;};
if (st != 1 &&st != 2 && st != 6 && st != 7 &&(ch==';')) break;
if (st==11||st==6) {ident.append(ch);}
if (st==5) {keyword.append(ch);
} else {
if ((keyword.CmpNoCase(wxT("from"))==0)) {
ident.Clear();
isfrom=true;
} else if (keyword.CmpNoCase(wxT("join"))==0) {
list_table.Append(wxT(","));
ident.Clear();
isfrom=true;
} else if (keyword.CmpNoCase(wxT("on"))==0) {
list_table.Append(wxT(","));
isfrom=false;
}else if (keyword.CmpNoCase(wxT("where"))==0) {
//list_table.Append(ident);
isfrom=false;
break;
}
if (!keyword.IsEmpty()) keyword.Clear();
}
if ((ch == '{' || ch == '}' ||
ch == '[' || ch == ']' ||
ch == '(' || ch == ')') &&
st != 1 &&st != 2 && st != 6 && st != 7)
{
match = BraceMatch(pos);
if (match == wxSTC_INVALID_POSITION)
{
BraceBadLight(pos);
break;
} else
{
pos=match;
ident.Clear();
}
}
if (st != 1 &&st != 2 && st != 6 && st != 7 &&(ch==';')) break;
if ((st==10||st==0)&&(!ident.IsEmpty())) {
if (isfrom) {
list_table.Append(wxT(" "));
list_table.Append(ident);
if (ch==',') list_table.Append(ch);
//if (!name.IsEmpty()) alias=ident; else name=ident;
}
ident.Clear();
}
pos++;
}
if (isfrom&&(!ident.IsEmpty())) {list_table.Append(wxT(" "));list_table.Append(ident);};
event.Skip();
}
@ -954,13 +1149,95 @@ void ctlSQLBox::OnAutoComplete(wxCommandEvent &rev)
tab_ret = tab_complete(what.mb_str(wxConvUTF8), 0, what.Len() + 1, m_database);
else
tab_ret = tab_complete(what.mb_str(wxConvUTF8), spaceidx + 1, what.Len() + 1, m_database);
if (tab_ret == NULL || tab_ret[0] == '\0')
return; /* No autocomplete available for this string */
wxString wxRet = wxString(tab_ret, wxConvUTF8);
free(tab_ret);
wxString wxRet;
if (tab_ret == NULL || tab_ret[0] == '\0'){
int l=0;
for (int kk=what.Len()-2;kk>=0;kk--) {
//char c=myStringChars.data[kk];
if ( what[kk]<'0') break;
l++;
}
wxString f_name;
if (l>0) {
wxString alias=what.substr(what.Len()-1-l,l);
wxString lst=list_table;
wxString table;
//alias.Replace(wxT("."), wxT(""));
lst.Replace(wxT("\""), wxT(""));
wxStringTokenizer tokenizer(lst, wxT(" ,"));
wxString prev;
bool found=false;
int p=0;
while ( tokenizer.HasMoreTokens() )
{
wxString token = tokenizer.GetNextToken();
if (token.IsEmpty()) {p=0; continue;}
found=token.CmpNoCase(alias)==0;
if (tokenizer.GetLastDelimiter()==' '&&found) {
table=token;
break;
}
if ((tokenizer.GetLastDelimiter()==',')&&found) {
if (p==1) table=prev; else table=token;
break;
}
if (found) {if (p==1) table=prev; else table=token; break;}
prev=token;
p++;
}
if (found) {
wxString sql=wxT("select string_agg(a.attname,E'\t') from pg_attribute a where a.attrelid = (select oid from pg_class p where relname=") +qtConnString(table)
+wxT(") and a.attisdropped IS FALSE and a.attnum>=0 order by 1");
//pgSet *res = m_database->ExecuteSet(sql);
prev= m_database->ExecuteScalar(sql);
AutoCompShow(0, prev);
return;
}
//list_table.Find(alias
}
l=0;
for (int kk=what.Len()-1;kk>=0;kk--) {
//char c=myStringChars.data[kk];
if ( what[kk]<'0') break;
l++;
}
if (l==0) return;
f_name=what.Right(l);
what=f_name;
size_t i,
lo = 0,
hi = m_name->Count();
int res;
while ( lo < hi ) {
i = (lo + hi)/2;
if (m_name->Item(i).StartsWith(f_name)) break;
res= f_name.CmpNoCase(m_name->Item(i));
//res = wxStrcmp(sz, m_pItems[i]);
if ( res < 0 )
hi = i;
else if ( res > 0 )
lo = i + 1;
else
{ break; }// i ok
}
if (lo >= hi) return;
int k=i;
while ( k>=0&&m_name->Item(k).StartsWith(f_name) ) k--;
k++;
wxString prev;
while ( (k<m_name->GetCount())&&m_name->Item(k).StartsWith(f_name) )
{
if (prev!=m_name->Item(k)) wxRet+=m_name->Item(k)+wxT("\t");
prev=m_name->Item(k);
k++;
};
spaceidx = what.Len()-1;
spaceidx = -1;
//return; /* No autocomplete available for this string */
} else {
wxRet = wxString(tab_ret, wxConvUTF8);
free(tab_ret);
}
// Switch to the generic list control. Native doesn't play well with
// autocomplete on Mac.
#ifdef __WXMAC__
@ -1043,11 +1320,11 @@ CharacterRange ctlSQLBox::RegexFindText(int minPos, int maxPos, const wxString &
ft.lpstrText = (char *)(const char *)buf;
//íå êîìïèëèðîâàëàñü ñ wx 2.8.12
//if (SendMsg(2150, wxSTC_FIND_REGEXP, (long)&ft) == -1)
//{
// ft.chrgText.cpMin = -1;
// ft.chrgText.cpMax = -1;
//}
if (SendMsg(2150, wxSTC_FIND_REGEXP, (long)&ft) == -1)
{
ft.chrgText.cpMin = -1;
ft.chrgText.cpMax = -1;
}
return ft.chrgText;
}

View file

@ -743,7 +743,25 @@ frmQuery::frmQuery(frmMain *form, const wxString &_title, pgConn *_conn, const w
queryMenu->Enable(MNU_CLEARHISTORY, false);
setTools(false);
lastFileFormat = settings->GetUnicodeFile();
// Load function name
pgSet *functions;
wxString def_f;
wxString def_name;
functions = conn->ExecuteSet(wxT("select pg_get_function_arguments(oid) def,proname,pronargs nargs from pg_proc where pronargs<>0 order by proname,pronargs"));
if (functions)
{
//name_func.Init(true);
while (!functions->Eof())
{
def_f = functions->GetVal(wxT("def"));
def_name = functions->GetVal(wxT("proname"));
def_func.Add(def_f);
name_func.Add(def_name);
functions->MoveNext();
}
name_func.Sort();
delete functions;
}
// Note that under GTK+, SetMaxLength() function may only be used with single line text controls.
// (see http://docs.wxwidgets.org/2.8/wx_wxtextctrl.html#wxtextctrlsetmaxlength)
#ifndef __WXGTK__
@ -756,7 +774,8 @@ frmQuery::frmQuery(frmMain *form, const wxString &_title, pgConn *_conn, const w
frmQuery::~frmQuery()
{
closing = true;
if (!name_func.IsEmpty()) name_func.Clear();
if (!def_func.IsEmpty()) def_func.Clear();
// Save frmQuery Perspective
settings->Write(wxT("frmQuery/Perspective-") + wxString(FRMQUERY_PERSPECTIVE_VER), manager.SavePerspective());
@ -1946,6 +1965,8 @@ void frmQuery::OnPositionStc(wxStyledTextEvent &event)
editMenu->Enable(MNU_AUTOEDITOBJECT, selCount > 0);
wxString pos;
pos.Printf(_("Ln %d, Col %d, Ch %d"), sqlQuery->LineFromPosition(sqlQuery->GetCurrentPos()) + 1, sqlQuery->GetColumn(sqlQuery->GetCurrentPos()) + 1, sqlQuery->GetCurrentPos() + 1);
//pos.Printf(_("Ln %d, Col %d, Ch %d, st %d"), sqlQuery->LineFromPosition(sqlQuery->GetCurrentPos()) + 1, sqlQuery->GetColumn(sqlQuery->GetCurrentPos()) + 1, sqlQuery->GetCurrentPos() + 1,sqlQuery->GetStyleAt(sqlQuery->GetCurrentPos() - 1));
SetStatusText(pos, STATUSPOS_POS);
if (selCount < 1)
pos = wxEmptyString;
@ -4011,6 +4032,7 @@ void frmQuery::SqlBookAddPage()
// Probably not needed, as the line above should trigger the PageChange event
sqlQuery = box;
sqlQuery->SetAutoReplaceList(autoreplace);
sqlQuery->SetDefFunction(name_func, def_func);
}
void frmQuery::SqlBookDisconnectPage(ctlSQLBox *box)

View file

@ -73,7 +73,7 @@ public:
void UpdateLineNumber();
wxString ExternalFormat();
void AbortProcess();
void SetDefFunction(wxArrayString &name, wxArrayString &def);
CharacterRange RegexFindText(int minPos, int maxPos, const wxString &text);
// Having multiple SQL tabs warrants the following properties to be tracked per tab
@ -104,6 +104,11 @@ private:
void OnPositionStc(wxStyledTextEvent &event);
void OnMarginClick(wxStyledTextEvent &event);
queryMacroList *autoreplace;
wxArrayString *m_name; // field proname
wxArrayString *m_def; // finction arguments
wxString list_table; // list table from section
wxString calltip;
int ct_hl;
dlgFindReplace *m_dlgFindReplace;
pgConn *m_database;
bool m_autoIndent, m_autocompDisabled;

View file

@ -135,7 +135,8 @@ private:
wxButton *btnDeleteCurrent;
wxButton *btnDeleteAll;
wxArrayString histoQueries;
wxArrayString def_func;
wxArrayString name_func;
ctlAuiNotebook *sqlQueryBook; //container for all SQL tabs
size_t sqlQueryCounter; //for initial tab names
ctlSQLBox *sqlQueryExec; //currently executing SQL tab