Attempt to add autocomplete+calltips to the qt version of fteqccgui.
git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5649 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
parent
d0b7519242
commit
19a2ecb99e
3 changed files with 612 additions and 202 deletions
|
@ -19,6 +19,7 @@ void GUI_RevealOptions(void);
|
||||||
int GUIprintf(const char *msg, ...);
|
int GUIprintf(const char *msg, ...);
|
||||||
|
|
||||||
pbool GenBuiltinsList(char *buffer, int buffersize);
|
pbool GenBuiltinsList(char *buffer, int buffersize);
|
||||||
|
pbool GenAutoCompleteList(char *prefix, char *buffer, int buffersize);
|
||||||
|
|
||||||
extern char parameters[16384];
|
extern char parameters[16384];
|
||||||
|
|
||||||
|
|
|
@ -3,8 +3,6 @@
|
||||||
/*Todo (in no particular order):
|
/*Todo (in no particular order):
|
||||||
tooltips for inspecting variables/types.
|
tooltips for inspecting variables/types.
|
||||||
variables/watch list.
|
variables/watch list.
|
||||||
calltips for argument info
|
|
||||||
autocompletion calltips, for people who can't remember function names
|
|
||||||
initial open project prompt
|
initial open project prompt
|
||||||
shpuld's styling
|
shpuld's styling
|
||||||
decompiler output saving
|
decompiler output saving
|
||||||
|
@ -47,6 +45,9 @@ extern int fl_tabsize;
|
||||||
extern char enginebinary[MAX_OSPATH];
|
extern char enginebinary[MAX_OSPATH];
|
||||||
extern char enginebasedir[MAX_OSPATH];
|
extern char enginebasedir[MAX_OSPATH];
|
||||||
extern char enginecommandline[8192];
|
extern char enginecommandline[8192];
|
||||||
|
|
||||||
|
extern QCC_def_t *sourcefilesdefs[];
|
||||||
|
extern int sourcefilesnumdefs;
|
||||||
};
|
};
|
||||||
static char *cmdlineargs;
|
static char *cmdlineargs;
|
||||||
|
|
||||||
|
@ -60,7 +61,7 @@ template<class T> inline T cpprealloc(T p, size_t s) {return static_cast<T>(real
|
||||||
#define STRINGIFY2(s) #s
|
#define STRINGIFY2(s) #s
|
||||||
#define STRINGIFY(s) STRINGIFY2(s)
|
#define STRINGIFY(s) STRINGIFY2(s)
|
||||||
|
|
||||||
|
static QProcess *qcdebugger;
|
||||||
static void DebuggerStop(void);
|
static void DebuggerStop(void);
|
||||||
static bool DebuggerSendCommand(const char *msg, ...);
|
static bool DebuggerSendCommand(const char *msg, ...);
|
||||||
static void DebuggerStart(void);
|
static void DebuggerStart(void);
|
||||||
|
@ -407,9 +408,120 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class WrappedQsciScintilla:public QsciScintilla
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
WrappedQsciScintilla(QWidget *parent):QsciScintilla(parent){}
|
||||||
|
|
||||||
|
char *WordUnderCursor(char *word, int wordsize, char *term, int termsize, int position)
|
||||||
|
{
|
||||||
|
unsigned char linebuf[1024];
|
||||||
|
long charidx;
|
||||||
|
long lineidx;
|
||||||
|
long len;
|
||||||
|
pbool noafter = (position==-2);
|
||||||
|
|
||||||
|
if (position == -3)
|
||||||
|
{
|
||||||
|
len = SendScintilla(QsciScintillaBase::SCI_GETSELTEXT, NULL);
|
||||||
|
if (len > 0 && len < wordsize)
|
||||||
|
{
|
||||||
|
len = SendScintilla(QsciScintillaBase::SCI_GETSELTEXT, word);
|
||||||
|
if (len>0)
|
||||||
|
return word;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (position < 0)
|
||||||
|
position = SendScintilla(QsciScintillaBase::SCI_GETCURRENTPOS);
|
||||||
|
|
||||||
|
lineidx = SendScintilla(QsciScintillaBase::SCI_LINEFROMPOSITION, position);
|
||||||
|
charidx = position - SendScintilla(QsciScintillaBase::SCI_POSITIONFROMLINE, lineidx);
|
||||||
|
|
||||||
|
len = SendScintilla(QsciScintillaBase::SCI_LINELENGTH, lineidx);
|
||||||
|
if (len >= sizeof(linebuf))
|
||||||
|
{
|
||||||
|
*word = 0;
|
||||||
|
return word;
|
||||||
|
}
|
||||||
|
len = SendScintilla(QsciScintillaBase::SCI_GETLINE, lineidx, linebuf);
|
||||||
|
linebuf[len] = 0;
|
||||||
|
if (charidx >= len)
|
||||||
|
charidx = len-1;
|
||||||
|
|
||||||
|
if (noafter) //truncate it here if we're not meant to be reading anything after.
|
||||||
|
linebuf[charidx] = 0;
|
||||||
|
|
||||||
|
if (word)
|
||||||
|
{
|
||||||
|
//skip back to the start of the word
|
||||||
|
while(charidx > 0 && (
|
||||||
|
(linebuf[charidx-1] >= 'a' && linebuf[charidx-1] <= 'z') ||
|
||||||
|
(linebuf[charidx-1] >= 'A' && linebuf[charidx-1] <= 'Z') ||
|
||||||
|
(linebuf[charidx-1] >= '0' && linebuf[charidx-1] <= '9') ||
|
||||||
|
linebuf[charidx-1] == '_' || linebuf[charidx-1] == ':' ||
|
||||||
|
linebuf[charidx-1] >= 128
|
||||||
|
))
|
||||||
|
{
|
||||||
|
charidx--;
|
||||||
|
}
|
||||||
|
//copy the result out
|
||||||
|
lineidx = 0;
|
||||||
|
wordsize--;
|
||||||
|
while (wordsize && (
|
||||||
|
(linebuf[charidx] >= 'a' && linebuf[charidx] <= 'z') ||
|
||||||
|
(linebuf[charidx] >= 'A' && linebuf[charidx] <= 'Z') ||
|
||||||
|
(linebuf[charidx] >= '0' && linebuf[charidx] <= '9') ||
|
||||||
|
linebuf[charidx] == '_' || linebuf[charidx] == ':' ||
|
||||||
|
linebuf[charidx] >= 128
|
||||||
|
))
|
||||||
|
{
|
||||||
|
word[lineidx++] = linebuf[charidx++];
|
||||||
|
wordsize--;
|
||||||
|
}
|
||||||
|
word[lineidx++] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (term)
|
||||||
|
{
|
||||||
|
//skip back to the start of the word
|
||||||
|
while(charidx > 0 && (
|
||||||
|
(linebuf[charidx-1] >= 'a' && linebuf[charidx-1] <= 'z') ||
|
||||||
|
(linebuf[charidx-1] >= 'A' && linebuf[charidx-1] <= 'Z') ||
|
||||||
|
(linebuf[charidx-1] >= '0' && linebuf[charidx-1] <= '9') ||
|
||||||
|
linebuf[charidx-1] == '_' || linebuf[charidx-1] == ':' || linebuf[charidx-1] == '.' ||
|
||||||
|
linebuf[charidx-1] == '[' || linebuf[charidx-1] == ']' ||
|
||||||
|
linebuf[charidx-1] >= 128
|
||||||
|
))
|
||||||
|
{
|
||||||
|
charidx--;
|
||||||
|
}
|
||||||
|
//copy the result out
|
||||||
|
lineidx = 0;
|
||||||
|
termsize--;
|
||||||
|
while (termsize && (
|
||||||
|
(linebuf[charidx] >= 'a' && linebuf[charidx] <= 'z') ||
|
||||||
|
(linebuf[charidx] >= 'A' && linebuf[charidx] <= 'Z') ||
|
||||||
|
(linebuf[charidx] >= '0' && linebuf[charidx] <= '9') ||
|
||||||
|
linebuf[charidx] == '_' || linebuf[charidx] == ':' || linebuf[charidx] == '.' ||
|
||||||
|
linebuf[charidx] == '[' || linebuf[charidx] == ']' ||
|
||||||
|
linebuf[charidx] >= 128
|
||||||
|
))
|
||||||
|
{
|
||||||
|
term[lineidx++] = linebuf[charidx++];
|
||||||
|
termsize--;
|
||||||
|
}
|
||||||
|
term[lineidx++] = 0;
|
||||||
|
}
|
||||||
|
return word;
|
||||||
|
}
|
||||||
|
protected:
|
||||||
|
void contextMenuEvent(QContextMenuEvent *event);
|
||||||
|
};
|
||||||
|
|
||||||
class documentlist : public QAbstractListModel
|
class documentlist : public QAbstractListModel
|
||||||
{
|
{
|
||||||
QsciScintilla *s; //this is the widget that we load our documents into
|
WrappedQsciScintilla *s; //this is the widget that we load our documents into
|
||||||
|
|
||||||
int numdocuments;
|
int numdocuments;
|
||||||
struct document_s
|
struct document_s
|
||||||
|
@ -480,7 +592,7 @@ class documentlist : public QAbstractListModel
|
||||||
}
|
}
|
||||||
void UpdateTitle(void);
|
void UpdateTitle(void);
|
||||||
public:
|
public:
|
||||||
documentlist(QsciScintilla *editor)
|
documentlist(WrappedQsciScintilla *editor)
|
||||||
{
|
{
|
||||||
s = editor;
|
s = editor;
|
||||||
numdocuments = 0;
|
numdocuments = 0;
|
||||||
|
@ -868,6 +980,18 @@ public:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
connect(s, &QsciScintillaBase::SCN_CHARADDED, [=](int charadded)
|
||||||
|
{
|
||||||
|
if (charadded == '(')
|
||||||
|
{
|
||||||
|
int pos = s->SendScintilla(QsciScintillaBase::SCI_GETCURRENTPOS);
|
||||||
|
char *tooltext = GetCalltipForLine(pos-1);
|
||||||
|
//tooltip_editor = NULL;
|
||||||
|
if (tooltext)
|
||||||
|
s->SendScintilla(QsciScintillaBase::SCI_CALLTIPSHOW, pos, tooltext);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
s->setUtf8(ed->savefmt != UTF_ANSI);
|
s->setUtf8(ed->savefmt != UTF_ANSI);
|
||||||
s->setText(QString(file));
|
s->setText(QString(file));
|
||||||
|
|
||||||
|
@ -927,6 +1051,155 @@ public:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char *GetCalltipForLine(int cursorpos) //calltips are used for tooltips too, so there's some extra weirdness in here
|
||||||
|
{
|
||||||
|
static char buffer[1024];
|
||||||
|
char wordbuf[256], *text;
|
||||||
|
char term[256];
|
||||||
|
char *defname;
|
||||||
|
defname = s->WordUnderCursor(wordbuf, sizeof(wordbuf), term, sizeof(term), cursorpos);
|
||||||
|
if (!*defname)
|
||||||
|
return NULL;
|
||||||
|
else if (globalstable.numbuckets)
|
||||||
|
{
|
||||||
|
QCC_def_t *def;
|
||||||
|
int fno;
|
||||||
|
int line;
|
||||||
|
int best, bestline;
|
||||||
|
char *macro = QCC_PR_CheckCompConstTooltip(defname, buffer, buffer + sizeof(buffer));
|
||||||
|
if (macro && *macro)
|
||||||
|
return macro;
|
||||||
|
|
||||||
|
/*if (dwell)
|
||||||
|
{
|
||||||
|
tooltip_editor = NULL;
|
||||||
|
*tooltip_variable = 0;
|
||||||
|
tooltip_position = 0;
|
||||||
|
*tooltip_type = 0;
|
||||||
|
*tooltip_comment = 0;
|
||||||
|
}*/
|
||||||
|
|
||||||
|
line = s->SendScintilla(QsciScintillaBase::SCI_LINEFROMPOSITION, cursorpos);
|
||||||
|
|
||||||
|
for (best = 0,bestline=0, fno = 1; fno < numfunctions; fno++)
|
||||||
|
{
|
||||||
|
if (line > functions[fno].line && bestline < functions[fno].line)
|
||||||
|
{
|
||||||
|
if (!strcmp(curdoc->fname, functions[fno].filen))
|
||||||
|
{
|
||||||
|
best = fno;
|
||||||
|
bestline = functions[fno].line;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (best)
|
||||||
|
{
|
||||||
|
if (strstr(functions[best].name, "::"))
|
||||||
|
{
|
||||||
|
QCC_type_t *type;
|
||||||
|
char tmp[256];
|
||||||
|
char *c;
|
||||||
|
QC_strlcpy(tmp, functions[best].name, sizeof(tmp));
|
||||||
|
c = strstr(tmp, "::");
|
||||||
|
if (c)
|
||||||
|
*c = 0;
|
||||||
|
type = QCC_TypeForName(tmp);
|
||||||
|
|
||||||
|
if (type->type == ev_entity)
|
||||||
|
{
|
||||||
|
QCC_def_t *def;
|
||||||
|
QC_snprintfz(tmp, sizeof(tmp), "%s::__m%s", type->name, term);
|
||||||
|
|
||||||
|
for (fno = 0, def = NULL; fno < sourcefilesnumdefs && !def; fno++)
|
||||||
|
{
|
||||||
|
for (def = sourcefilesdefs[fno]; def; def = def->next)
|
||||||
|
{
|
||||||
|
if (def->scope && def->scope != &functions[best])
|
||||||
|
continue;
|
||||||
|
// OutputDebugString(def->name);
|
||||||
|
// OutputDebugString("\n");
|
||||||
|
if (!strcmp(def->name, tmp))
|
||||||
|
{
|
||||||
|
//FIXME: look at the scope's function to find the start+end of the function and filter based upon that, to show locals
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (def && def->type->type == ev_field)
|
||||||
|
{
|
||||||
|
// QC_strlcpy(tmp, term, sizeof(tmp));
|
||||||
|
QC_snprintfz(term, sizeof(term), "self.%s", tmp);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (fno = 0, def = NULL; fno < sourcefilesnumdefs && !def; fno++)
|
||||||
|
{
|
||||||
|
for (def = sourcefilesdefs[fno]; def; def = def->next)
|
||||||
|
{
|
||||||
|
if (def->scope && def->scope != &functions[best])
|
||||||
|
continue;
|
||||||
|
if (!strcmp(def->name, term))
|
||||||
|
{
|
||||||
|
//FIXME: look at the scope's function to find the start+end of the function and filter based upon that, to show locals
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (def && def->type->type == ev_field)
|
||||||
|
{
|
||||||
|
QC_strlcpy(tmp, term, sizeof(tmp));
|
||||||
|
QC_snprintfz(term, sizeof(term), "self.%s", tmp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//FIXME: we may need to display types too
|
||||||
|
for (fno = 0, def = NULL; fno < sourcefilesnumdefs && !def; fno++)
|
||||||
|
{
|
||||||
|
for (def = sourcefilesdefs[fno]; def; def = def->next)
|
||||||
|
{
|
||||||
|
if (def->scope)
|
||||||
|
continue;
|
||||||
|
if (!strcmp(def->name, defname))
|
||||||
|
{
|
||||||
|
//FIXME: look at the scope's function to find the start+end of the function and filter based upon that, to show locals
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (def)
|
||||||
|
{
|
||||||
|
char typebuf[1024];
|
||||||
|
char valuebuf[1024];
|
||||||
|
if (def->constant && def->type->type == ev_float)
|
||||||
|
QC_snprintfz(valuebuf, sizeof(valuebuf), " = %g", def->symboldata[def->ofs]._float);
|
||||||
|
else if (def->constant && def->type->type == ev_integer)
|
||||||
|
QC_snprintfz(valuebuf, sizeof(valuebuf), " = %i", def->symboldata[def->ofs]._int);
|
||||||
|
else if (def->constant && def->type->type == ev_vector)
|
||||||
|
QC_snprintfz(valuebuf, sizeof(valuebuf), " = '%g %g %g'", def->symboldata[def->ofs].vector[0], def->symboldata[def->ofs].vector[1], def->symboldata[def->ofs].vector[2]);
|
||||||
|
else
|
||||||
|
*valuebuf = 0;
|
||||||
|
//note function argument names do not persist beyond the function def. we might be able to read the function's localdefs for them, but that's unreliable/broken with builtins where they're most needed.
|
||||||
|
if (def->comment)
|
||||||
|
QC_snprintfz(buffer, sizeof(buffer)-1, "%s %s%s\r\n%s", TypeName(def->type, typebuf, sizeof(typebuf)), def->name, valuebuf, def->comment);
|
||||||
|
else
|
||||||
|
QC_snprintfz(buffer, sizeof(buffer)-1, "%s %s%s", TypeName(def->type, typebuf, sizeof(typebuf)), def->name, valuebuf);
|
||||||
|
|
||||||
|
text = buffer;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
text = NULL;
|
||||||
|
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return NULL;//"Type info not available. Compile first.";
|
||||||
|
}
|
||||||
|
|
||||||
bool annotate(const char *line)
|
bool annotate(const char *line)
|
||||||
{
|
{
|
||||||
auto filename = line+6;
|
auto filename = line+6;
|
||||||
|
@ -1124,6 +1397,47 @@ public:
|
||||||
|
|
||||||
DebuggerSendCommand("qcbreakpoint %i \"%s\" %i\n", mode, curdoc->fname, curdoc->cursorline);
|
DebuggerSendCommand("qcbreakpoint %i \"%s\" %i\n", mode, curdoc->fname, curdoc->cursorline);
|
||||||
}
|
}
|
||||||
|
/*void setMarkerLine(int linenum)
|
||||||
|
{ //moves the 'current-line' marker to the active document and current line
|
||||||
|
for (int i = 0; i < numdocuments; i++)
|
||||||
|
{
|
||||||
|
docstacklock lock(this, docs[i]);
|
||||||
|
s->SendScintilla(QsciScintillaBase::SCI_MARKERDELETEALL, 1);
|
||||||
|
s->SendScintilla(QsciScintillaBase::SCI_MARKERDELETEALL, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (linenum <= 0)
|
||||||
|
return;
|
||||||
|
s->SendScintilla(QsciScintillaBase::SCI_MARKERADD, linenum-1, 1);
|
||||||
|
s->SendScintilla(QsciScintillaBase::SCI_MARKERADD, linenum-1, 2);
|
||||||
|
}*/
|
||||||
|
void setNextStatement(void)
|
||||||
|
{
|
||||||
|
if (!curdoc)
|
||||||
|
return;
|
||||||
|
if (!qcdebugger)
|
||||||
|
return; //can't move it if we're not running.
|
||||||
|
|
||||||
|
DebuggerSendCommand("qcjump \"%s\" %i\n", curdoc->fname, curdoc->cursorline);
|
||||||
|
}
|
||||||
|
void autoComplete(void)
|
||||||
|
{
|
||||||
|
if (!curdoc)
|
||||||
|
return;
|
||||||
|
|
||||||
|
char word[256];
|
||||||
|
char suggestions[65536];
|
||||||
|
s->WordUnderCursor(word, sizeof(word), NULL, 0, -2);
|
||||||
|
if (*word && GenAutoCompleteList(word, suggestions, sizeof(suggestions)))
|
||||||
|
{
|
||||||
|
s->SendScintilla(QsciScintillaBase::SCI_AUTOCSETFILLUPS, ".,[<>(*/+-=\t\n");
|
||||||
|
s->SendScintilla(QsciScintillaBase::SCI_AUTOCSHOW, strlen(word), suggestions);
|
||||||
|
}
|
||||||
|
|
||||||
|
//s->SendScintilla(QsciScintillaBase::SCI_CALLTIPSHOW, (int)0, "hello world");
|
||||||
|
|
||||||
|
//SCI_CALLTIPSHOW pos, "text"
|
||||||
|
}
|
||||||
void setNext(void)
|
void setNext(void)
|
||||||
{
|
{
|
||||||
if (!curdoc)
|
if (!curdoc)
|
||||||
|
@ -1304,7 +1618,7 @@ public:
|
||||||
static class guimainwindow : public QMainWindow
|
static class guimainwindow : public QMainWindow
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
QsciScintilla s;
|
WrappedQsciScintilla s;
|
||||||
QSplitter leftrightsplit;
|
QSplitter leftrightsplit;
|
||||||
QSplitter logsplit;
|
QSplitter logsplit;
|
||||||
QSplitter leftsplit;
|
QSplitter leftsplit;
|
||||||
|
@ -1318,215 +1632,231 @@ public:
|
||||||
private:
|
private:
|
||||||
void CreateMenus(void)
|
void CreateMenus(void)
|
||||||
{
|
{
|
||||||
auto fileMenu = menuBar()->addMenu(tr("&File"));
|
{
|
||||||
|
auto fileMenu = menuBar()->addMenu(tr("&File"));
|
||||||
|
|
||||||
//editor UI things
|
//editor UI things
|
||||||
auto fileopen = new QAction(tr("Open"), this);
|
auto fileopen = new QAction(tr("Open"), this);
|
||||||
fileMenu->addAction(fileopen);
|
fileMenu->addAction(fileopen);
|
||||||
fileopen->setShortcuts(QKeySequence::listFromString("Ctrl+O"));
|
fileopen->setShortcuts(QKeySequence::listFromString("Ctrl+O"));
|
||||||
connect(fileopen, &QAction::triggered, [=]()
|
connect(fileopen, &QAction::triggered, [=]()
|
||||||
{
|
|
||||||
GUIprintf("Ctrl+O hit\n");
|
|
||||||
});
|
|
||||||
auto filesave = new QAction(tr("Save"), this);
|
|
||||||
fileMenu->addAction(filesave);
|
|
||||||
filesave->setShortcuts(QKeySequence::listFromString("Ctrl+S"));
|
|
||||||
connect(filesave, &QAction::triggered, [=]()
|
|
||||||
{
|
|
||||||
if (!docs.saveDocument(NULL))
|
|
||||||
QMessageBox::critical(nullptr, "Error", QString::asprintf("Unable to save"));
|
|
||||||
});
|
|
||||||
|
|
||||||
auto prefs = new QAction(tr("&Preferences"), this);
|
|
||||||
fileMenu->addAction(prefs);
|
|
||||||
prefs->setShortcuts(QKeySequence::Preferences);
|
|
||||||
prefs->setStatusTip(tr("Reconfigure stuff"));
|
|
||||||
connect(prefs, &QAction::triggered, [](){(new optionswindow())->show();});
|
|
||||||
|
|
||||||
auto goline = new QAction(tr("Go to line"), this);
|
|
||||||
fileMenu->addAction(goline);
|
|
||||||
goline->setShortcuts(QKeySequence::listFromString("Ctrl+G"));
|
|
||||||
goline->setStatusTip(tr("Jump to line"));
|
|
||||||
connect(goline, &QAction::triggered, [=]()
|
|
||||||
{
|
|
||||||
struct grepargs_s
|
|
||||||
{
|
{
|
||||||
guimainwindow *mw;
|
GUIprintf("Ctrl+O hit\n");
|
||||||
QDialog *d;
|
});
|
||||||
QLineEdit *t;
|
auto filesave = new QAction(tr("Save"), this);
|
||||||
} args = {this, new QDialog()};
|
fileMenu->addAction(filesave);
|
||||||
args.t = new QLineEdit(QString(""));
|
filesave->setShortcuts(QKeySequence::listFromString("Ctrl+S"));
|
||||||
auto l = new QVBoxLayout;
|
connect(filesave, &QAction::triggered, [=]()
|
||||||
l->addWidget(args.t);
|
|
||||||
args.d->setLayout(l);
|
|
||||||
args.d->setWindowTitle("FTEQCC Go To Line");
|
|
||||||
args.t->installEventFilter(new keyEnterReceiver<grepargs_s>([](grepargs_s &ctx)
|
|
||||||
{
|
|
||||||
ctx.mw->docs.EditFile(NULL, atoi(ctx.t->text().toUtf8().data()));
|
|
||||||
ctx.d->done(0);
|
|
||||||
}, args));
|
|
||||||
args.d->show();
|
|
||||||
});
|
|
||||||
|
|
||||||
auto godef = new QAction(tr("Go To Definition"), this);
|
|
||||||
fileMenu->addAction(godef);
|
|
||||||
godef->setShortcuts(QKeySequence::listFromString("F12"));
|
|
||||||
connect(godef, &QAction::triggered, [=]()
|
|
||||||
{
|
|
||||||
struct grepargs_s
|
|
||||||
{
|
{
|
||||||
guimainwindow *mw;
|
if (!docs.saveDocument(NULL))
|
||||||
QDialog *d;
|
QMessageBox::critical(nullptr, "Error", QString::asprintf("Unable to save"));
|
||||||
QLineEdit *t;
|
});
|
||||||
} args = {this, new QDialog()};
|
|
||||||
args.t = new QLineEdit(this->s.selectedText());
|
|
||||||
auto l = new QVBoxLayout;
|
|
||||||
l->addWidget(args.t);
|
|
||||||
args.d->setLayout(l);
|
|
||||||
args.d->setWindowTitle("Go To Definition");
|
|
||||||
args.t->installEventFilter(new keyEnterReceiver<grepargs_s>([](grepargs_s &ctx)
|
|
||||||
{
|
|
||||||
GoToDefinition(ctx.t->text().toUtf8().data());
|
|
||||||
ctx.d->done(0);
|
|
||||||
}, args));
|
|
||||||
args.d->show();
|
|
||||||
});
|
|
||||||
|
|
||||||
auto find = new QAction(tr("Find"), this);
|
auto prefs = new QAction(tr("&Preferences"), this);
|
||||||
fileMenu->addAction(find);
|
fileMenu->addAction(prefs);
|
||||||
find->setShortcuts(QKeySequence::listFromString("Ctrl+F"));
|
prefs->setShortcuts(QKeySequence::Preferences);
|
||||||
find->setStatusTip(tr("Search through all project files"));
|
prefs->setStatusTip(tr("Reconfigure stuff"));
|
||||||
connect(find, &QAction::triggered, [=]()
|
connect(prefs, &QAction::triggered, [](){(new optionswindow())->show();});
|
||||||
{
|
|
||||||
struct grepargs_s
|
auto goline = new QAction(tr("Go to line"), this);
|
||||||
|
fileMenu->addAction(goline);
|
||||||
|
goline->setShortcuts(QKeySequence::listFromString("Ctrl+G"));
|
||||||
|
goline->setStatusTip(tr("Jump to line"));
|
||||||
|
connect(goline, &QAction::triggered, [=]()
|
||||||
{
|
{
|
||||||
guimainwindow *mw;
|
struct grepargs_s
|
||||||
QDialog *d;
|
|
||||||
QLineEdit *t;
|
|
||||||
} args = {this, new QDialog()};
|
|
||||||
args.t = new QLineEdit(this->s.selectedText());
|
|
||||||
auto l = new QVBoxLayout;
|
|
||||||
l->addWidget(args.t);
|
|
||||||
args.d->setLayout(l);
|
|
||||||
args.d->setWindowTitle("FTEQCC Find");
|
|
||||||
args.t->installEventFilter(new keyEnterReceiver<grepargs_s>([](grepargs_s &ctx)
|
|
||||||
{
|
{
|
||||||
ctx.mw->s.findFirst(ctx.t->text(), false, false, false, true);
|
guimainwindow *mw;
|
||||||
ctx.d->done(0);
|
QDialog *d;
|
||||||
}, args));
|
QLineEdit *t;
|
||||||
args.d->show();
|
} args = {this, new QDialog()};
|
||||||
});
|
args.t = new QLineEdit(QString(""));
|
||||||
connect(new QShortcut(QKeySequence(tr("F3", "File|FindNext")), this), &QShortcut::activated,
|
auto l = new QVBoxLayout;
|
||||||
[=]()
|
l->addWidget(args.t);
|
||||||
{
|
args.d->setLayout(l);
|
||||||
s.findNext();
|
args.d->setWindowTitle("FTEQCC Go To Line");
|
||||||
});
|
args.t->installEventFilter(new keyEnterReceiver<grepargs_s>([](grepargs_s &ctx)
|
||||||
|
{
|
||||||
|
ctx.mw->docs.EditFile(NULL, atoi(ctx.t->text().toUtf8().data()));
|
||||||
|
ctx.d->done(0);
|
||||||
|
}, args));
|
||||||
|
args.d->show();
|
||||||
|
});
|
||||||
|
|
||||||
auto grep = new QAction(tr("Grep"), this);
|
auto find = new QAction(tr("Find In File"), this);
|
||||||
fileMenu->addAction(grep);
|
fileMenu->addAction(find);
|
||||||
grep->setShortcuts(QKeySequence::listFromString("Ctrl+Shift+G"));
|
find->setShortcuts(QKeySequence::listFromString("Ctrl+F"));
|
||||||
grep->setStatusTip(tr("Search through all project files"));
|
find->setStatusTip(tr("Search for a token in the current file"));
|
||||||
connect(grep, &QAction::triggered, [=]()
|
connect(find, &QAction::triggered, [=]()
|
||||||
{
|
|
||||||
struct grepargs_s
|
|
||||||
{
|
{
|
||||||
guimainwindow *mw;
|
struct grepargs_s
|
||||||
QDialog *d;
|
|
||||||
QLineEdit *t;
|
|
||||||
} args = {this, new QDialog()};
|
|
||||||
args.t = new QLineEdit(this->s.selectedText());
|
|
||||||
auto l = new QVBoxLayout;
|
|
||||||
l->addWidget(args.t);
|
|
||||||
args.d->setLayout(l);
|
|
||||||
args.d->setWindowTitle("FTEQCC Grep Project Files");
|
|
||||||
args.t->installEventFilter(new keyEnterReceiver<grepargs_s>([](grepargs_s &ctx)
|
|
||||||
{
|
{
|
||||||
ctx.mw->files.GrepAll(ctx.t->text().toUtf8().data());
|
guimainwindow *mw;
|
||||||
ctx.d->done(0);
|
QDialog *d;
|
||||||
}, args));
|
QLineEdit *t;
|
||||||
args.d->show();
|
} args = {this, new QDialog()};
|
||||||
});
|
args.t = new QLineEdit(this->s.selectedText());
|
||||||
|
auto l = new QVBoxLayout;
|
||||||
|
l->addWidget(args.t);
|
||||||
|
args.d->setLayout(l);
|
||||||
|
args.d->setWindowTitle("Find In File");
|
||||||
|
args.t->installEventFilter(new keyEnterReceiver<grepargs_s>([](grepargs_s &ctx)
|
||||||
|
{
|
||||||
|
ctx.mw->s.findFirst(ctx.t->text(), false, false, false, true);
|
||||||
|
ctx.d->done(0);
|
||||||
|
}, args));
|
||||||
|
args.d->show();
|
||||||
|
});
|
||||||
|
connect(new QShortcut(QKeySequence(tr("F3", "File|FindNext")), this), &QShortcut::activated,
|
||||||
|
[=]()
|
||||||
|
{
|
||||||
|
s.findNext();
|
||||||
|
});
|
||||||
|
|
||||||
//convert to utf-8 chars
|
auto grep = new QAction(tr("Find In Project"), this);
|
||||||
//convert to Quake chars
|
fileMenu->addAction(grep);
|
||||||
|
grep->setShortcuts(QKeySequence::listFromString("Ctrl+Shift+F"));
|
||||||
|
grep->setStatusTip(tr("Search through all project files"));
|
||||||
|
connect(grep, &QAction::triggered, [=]()
|
||||||
|
{
|
||||||
|
struct grepargs_s
|
||||||
|
{
|
||||||
|
guimainwindow *mw;
|
||||||
|
QDialog *d;
|
||||||
|
QLineEdit *t;
|
||||||
|
} args = {this, new QDialog()};
|
||||||
|
args.t = new QLineEdit(this->s.selectedText());
|
||||||
|
auto l = new QVBoxLayout;
|
||||||
|
l->addWidget(args.t);
|
||||||
|
args.d->setLayout(l);
|
||||||
|
args.d->setWindowTitle("Find In Project");
|
||||||
|
args.t->installEventFilter(new keyEnterReceiver<grepargs_s>([](grepargs_s &ctx)
|
||||||
|
{
|
||||||
|
ctx.mw->files.GrepAll(ctx.t->text().toUtf8().data());
|
||||||
|
ctx.d->done(0);
|
||||||
|
}, args));
|
||||||
|
args.d->show();
|
||||||
|
});
|
||||||
|
|
||||||
auto convertunix = new QAction(tr("Convert to Unix Endings"), this);
|
auto quit = new QAction(tr("Quit"), this);
|
||||||
fileMenu->addAction(convertunix);
|
fileMenu->addAction(quit);
|
||||||
connect(convertunix, &QAction::triggered, [=]()
|
connect(quit, &QAction::triggered, [=]()
|
||||||
{
|
{
|
||||||
s.convertEols(QsciScintilla::EolUnix);
|
this->close();
|
||||||
s.setEolVisibility(false);
|
});
|
||||||
});
|
}
|
||||||
auto convertdos = new QAction(tr("Convert to DOS Endings"), this);
|
{
|
||||||
fileMenu->addAction(convertdos);
|
auto editMenu = menuBar()->addMenu(tr("&Edit"));
|
||||||
connect(convertdos, &QAction::triggered, [=]()
|
|
||||||
{
|
|
||||||
s.convertEols(QsciScintilla::EolWindows);
|
|
||||||
s.setEolVisibility(false);
|
|
||||||
});
|
|
||||||
|
|
||||||
auto quit = new QAction(tr("Quit"), this);
|
//undo
|
||||||
fileMenu->addAction(quit);
|
//redo
|
||||||
connect(quit, &QAction::triggered, [=]()
|
|
||||||
{
|
|
||||||
this->close();
|
|
||||||
});
|
|
||||||
|
|
||||||
|
auto godef = new QAction(tr("Go To Definition"), this);
|
||||||
|
editMenu->addAction(godef);
|
||||||
|
godef->setShortcuts(QKeySequence::listFromString("F12"));
|
||||||
|
connect(godef, &QAction::triggered, [=]()
|
||||||
|
{
|
||||||
|
struct grepargs_s
|
||||||
|
{
|
||||||
|
guimainwindow *mw;
|
||||||
|
QDialog *d;
|
||||||
|
QLineEdit *t;
|
||||||
|
} args = {this, new QDialog()};
|
||||||
|
args.t = new QLineEdit(this->s.selectedText());
|
||||||
|
auto l = new QVBoxLayout;
|
||||||
|
l->addWidget(args.t);
|
||||||
|
args.d->setLayout(l);
|
||||||
|
args.d->setWindowTitle("Go To Definition");
|
||||||
|
args.t->installEventFilter(new keyEnterReceiver<grepargs_s>([](grepargs_s &ctx)
|
||||||
|
{
|
||||||
|
GoToDefinition(ctx.t->text().toUtf8().data());
|
||||||
|
ctx.d->done(0);
|
||||||
|
}, args));
|
||||||
|
args.d->show();
|
||||||
|
});
|
||||||
|
|
||||||
auto debugMenu = menuBar()->addMenu(tr("&Debug"));
|
auto autocomplete = new QAction(tr("AutoComplete"), this);
|
||||||
auto debugrebuild = new QAction(tr("Rebuild"), this);
|
editMenu->addAction(autocomplete);
|
||||||
debugMenu->addAction(debugrebuild);
|
autocomplete->setShortcuts(QKeySequence::listFromString("Ctrl+Space"));
|
||||||
debugrebuild->setShortcuts(QKeySequence::listFromString("F7"));
|
connect(autocomplete, &QAction::triggered, [=]()
|
||||||
connect(debugrebuild, &QAction::triggered, [=]()
|
{
|
||||||
{
|
docs.autoComplete();
|
||||||
RunCompiler("", false);
|
});
|
||||||
});
|
auto convertunix = new QAction(tr("Convert to Unix Endings"), this);
|
||||||
auto debugsetnext = new QAction(tr("Set Next Statement"), this);
|
editMenu->addAction(convertunix);
|
||||||
debugMenu->addAction(debugsetnext);
|
connect(convertunix, &QAction::triggered, [=]()
|
||||||
debugsetnext->setShortcuts(QKeySequence::listFromString("F8"));
|
{
|
||||||
connect(debugsetnext, &QAction::triggered, [=]()
|
s.convertEols(QsciScintilla::EolUnix);
|
||||||
{
|
s.setEolVisibility(false);
|
||||||
//FIXME
|
});
|
||||||
});
|
auto convertdos = new QAction(tr("Convert to DOS Endings"), this);
|
||||||
auto debugresume = new QAction(tr("Resume"), this);
|
editMenu->addAction(convertdos);
|
||||||
debugMenu->addAction(debugresume);
|
connect(convertdos, &QAction::triggered, [=]()
|
||||||
debugresume->setShortcuts(QKeySequence::listFromString("F5"));
|
{
|
||||||
connect(debugresume, &QAction::triggered, [=]()
|
s.convertEols(QsciScintilla::EolWindows);
|
||||||
{
|
s.setEolVisibility(false);
|
||||||
if (!DebuggerSendCommand("qcresume\n"))
|
});
|
||||||
DebuggerStart(); //unable to send? assume its not running.
|
|
||||||
});
|
//convert to utf-8 chars
|
||||||
auto debugover = new QAction(tr("Step Over"), this);
|
//convert to Quake chars
|
||||||
debugMenu->addAction(debugover);
|
}
|
||||||
debugover->setShortcuts(QKeySequence::listFromString("F10"));
|
{
|
||||||
connect(debugover, &QAction::triggered, [=]()
|
auto debugMenu = menuBar()->addMenu(tr("&Debug"));
|
||||||
{
|
|
||||||
if (!DebuggerSendCommand("qcstep over\n"))
|
auto debugrebuild = new QAction(tr("Rebuild"), this);
|
||||||
DebuggerStart();
|
debugMenu->addAction(debugrebuild);
|
||||||
});
|
debugrebuild->setShortcuts(QKeySequence::listFromString("F7"));
|
||||||
auto debuginto = new QAction(tr("Step Into"), this);
|
connect(debugrebuild, &QAction::triggered, [=]()
|
||||||
debugMenu->addAction(debuginto);
|
{
|
||||||
debuginto->setShortcuts(QKeySequence::listFromString("F11"));
|
RunCompiler("", false);
|
||||||
connect(debuginto, &QAction::triggered, [=]()
|
});
|
||||||
{
|
auto debugsetnext = new QAction(tr("Set Next Statement"), this);
|
||||||
if (!DebuggerSendCommand("qcstep into\n"))
|
debugMenu->addAction(debugsetnext);
|
||||||
DebuggerStart();
|
debugsetnext->setShortcuts(QKeySequence::listFromString("F8"));
|
||||||
});
|
connect(debugsetnext, &QAction::triggered, [=]()
|
||||||
auto debugout = new QAction(tr("Step Out"), this);
|
{
|
||||||
debugMenu->addAction(debugout);
|
docs.setNextStatement();
|
||||||
debugout->setShortcuts(QKeySequence::listFromString("Shift+F11"));
|
});
|
||||||
connect(debugout, &QAction::triggered, [=]()
|
auto debugresume = new QAction(tr("Resume"), this);
|
||||||
{
|
debugMenu->addAction(debugresume);
|
||||||
if (!DebuggerSendCommand("qcstep out\n"))
|
debugresume->setShortcuts(QKeySequence::listFromString("F5"));
|
||||||
DebuggerStart();
|
connect(debugresume, &QAction::triggered, [=]()
|
||||||
});
|
{
|
||||||
auto debugbreak = new QAction(tr("Toggle Breakpoint"), this);
|
if (!DebuggerSendCommand("qcresume\n"))
|
||||||
debugMenu->addAction(debugbreak);
|
DebuggerStart(); //unable to send? assume its not running.
|
||||||
debugbreak->setShortcuts(QKeySequence::listFromString("F9"));
|
});
|
||||||
connect(debugbreak, &QAction::triggered, [=]()
|
auto debugover = new QAction(tr("Step Over"), this);
|
||||||
{
|
debugMenu->addAction(debugover);
|
||||||
docs.toggleBreak();
|
debugover->setShortcuts(QKeySequence::listFromString("F10"));
|
||||||
});
|
connect(debugover, &QAction::triggered, [=]()
|
||||||
|
{
|
||||||
|
if (!DebuggerSendCommand("qcstep over\n"))
|
||||||
|
DebuggerStart();
|
||||||
|
});
|
||||||
|
auto debuginto = new QAction(tr("Step Into"), this);
|
||||||
|
debugMenu->addAction(debuginto);
|
||||||
|
debuginto->setShortcuts(QKeySequence::listFromString("F11"));
|
||||||
|
connect(debuginto, &QAction::triggered, [=]()
|
||||||
|
{
|
||||||
|
if (!DebuggerSendCommand("qcstep into\n"))
|
||||||
|
DebuggerStart();
|
||||||
|
});
|
||||||
|
auto debugout = new QAction(tr("Step Out"), this);
|
||||||
|
debugMenu->addAction(debugout);
|
||||||
|
debugout->setShortcuts(QKeySequence::listFromString("Shift+F11"));
|
||||||
|
connect(debugout, &QAction::triggered, [=]()
|
||||||
|
{
|
||||||
|
if (!DebuggerSendCommand("qcstep out\n"))
|
||||||
|
DebuggerStart();
|
||||||
|
});
|
||||||
|
auto debugbreak = new QAction(tr("Toggle Breakpoint"), this);
|
||||||
|
debugMenu->addAction(debugbreak);
|
||||||
|
debugbreak->setShortcuts(QKeySequence::listFromString("F9"));
|
||||||
|
connect(debugbreak, &QAction::triggered, [=]()
|
||||||
|
{
|
||||||
|
docs.toggleBreak();
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -1597,6 +1927,52 @@ public:
|
||||||
}
|
}
|
||||||
} *mainwnd;
|
} *mainwnd;
|
||||||
|
|
||||||
|
|
||||||
|
void WrappedQsciScintilla::contextMenuEvent(QContextMenuEvent *event)
|
||||||
|
{
|
||||||
|
QMenu *menu = createStandardContextMenu();
|
||||||
|
static char blah[256];
|
||||||
|
|
||||||
|
if (*WordUnderCursor(blah, sizeof(blah), NULL, 0, -3))
|
||||||
|
{
|
||||||
|
menu->addSeparator();
|
||||||
|
connect(menu->addAction(tr("Go to definition")), &QAction::triggered, [=]()
|
||||||
|
{
|
||||||
|
GoToDefinition(blah);
|
||||||
|
});
|
||||||
|
connect(menu->addAction(tr("Find Usages")), &QAction::triggered, [=]()
|
||||||
|
{
|
||||||
|
mainwnd->files.GrepAll(blah);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
menu->addSeparator();
|
||||||
|
connect(menu->addAction(tr("Toggle Breakpoint")), &QAction::triggered, [=]()
|
||||||
|
{
|
||||||
|
mainwnd->docs.toggleBreak();
|
||||||
|
});
|
||||||
|
if (qcdebugger)
|
||||||
|
{
|
||||||
|
connect(menu->addAction(tr("Set Next Statement")), &QAction::triggered, [=]()
|
||||||
|
{
|
||||||
|
mainwnd->docs.setNextStatement();
|
||||||
|
});
|
||||||
|
connect(menu->addAction(tr("Resume")), &QAction::triggered, [=]()
|
||||||
|
{
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
connect(menu->addAction(tr("Start Debugging")), &QAction::triggered, [=]()
|
||||||
|
{
|
||||||
|
DebuggerStart();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
menu->exec(event->globalPos());
|
||||||
|
delete menu;
|
||||||
|
}
|
||||||
|
|
||||||
//called when progssrcname has changed.
|
//called when progssrcname has changed.
|
||||||
//progssrcname should already have been set.
|
//progssrcname should already have been set.
|
||||||
void UpdateFileList(void)
|
void UpdateFileList(void)
|
||||||
|
@ -2043,7 +2419,6 @@ int GUIFileSize(const char *fname)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static QProcess *qcdebugger;
|
|
||||||
static void DebuggerStop(void)
|
static void DebuggerStop(void)
|
||||||
{
|
{
|
||||||
if (qcdebugger)
|
if (qcdebugger)
|
||||||
|
|
|
@ -201,6 +201,40 @@ void GoToDefinition(const char *name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pbool GenAutoCompleteList(char *prefix, char *buffer, int buffersize)
|
||||||
|
{
|
||||||
|
QCC_def_t *def;
|
||||||
|
int prefixlen = strlen(prefix);
|
||||||
|
int usedbuffer = 0;
|
||||||
|
int l;
|
||||||
|
int fno;
|
||||||
|
for (fno = 0; fno < sourcefilesnumdefs; fno++)
|
||||||
|
{
|
||||||
|
for (def = sourcefilesdefs[fno]; def; def = def->next)
|
||||||
|
{
|
||||||
|
if (def->scope)
|
||||||
|
continue; //ignore locals, because we don't know where we are, and they're probably irrelevent.
|
||||||
|
|
||||||
|
//make sure it has the right prefix
|
||||||
|
if (!strncmp(def->name, prefix, prefixlen))
|
||||||
|
//but ignore it if its one of those special things that you're not meant to know about.
|
||||||
|
if (strcmp(def->name, "IMMEDIATE") && !strchr(def->name, ':') && !strchr(def->name, '.') && !strchr(def->name, '*') && !strchr(def->name, '['))
|
||||||
|
{
|
||||||
|
l = strlen(def->name);
|
||||||
|
if (l && usedbuffer+2+l < buffersize)
|
||||||
|
{
|
||||||
|
if (usedbuffer)
|
||||||
|
buffer[usedbuffer++] = ' ';
|
||||||
|
memcpy(buffer+usedbuffer, def->name, l);
|
||||||
|
usedbuffer += l;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
buffer[usedbuffer] = 0;
|
||||||
|
return usedbuffer>0;
|
||||||
|
}
|
||||||
|
|
||||||
static void GUI_WriteConfigLine(FILE *file, char *part1, char *part2, char *part3, char *desc)
|
static void GUI_WriteConfigLine(FILE *file, char *part1, char *part2, char *part3, char *desc)
|
||||||
{
|
{
|
||||||
int align = 0;
|
int align = 0;
|
||||||
|
|
Loading…
Reference in a new issue