1
0
Fork 0
forked from fte/fteqw

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:
Spoike 2020-03-14 17:38:55 +00:00
parent d0b7519242
commit 19a2ecb99e
3 changed files with 612 additions and 202 deletions

View file

@ -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];

View file

@ -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)

View file

@ -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;