diff --git a/engine/qclib/qcc_pr_comp.c b/engine/qclib/qcc_pr_comp.c
index c2ac73f3c..7f640efc9 100644
--- a/engine/qclib/qcc_pr_comp.c
+++ b/engine/qclib/qcc_pr_comp.c
@@ -4269,6 +4269,70 @@ QCC_statement_t *QCC_PR_SimpleStatement ( QCC_opcode_t *op, QCC_sref_t var_a, QC
 	return statement;
 }
 
+/*
+	Removes trailing statements, rewinding back to a known-safe position.
+*/
+void QCC_UngenerateStatements(int newstatementcount)
+{
+	int i;
+
+	//forget any indexes to statements if those statements are going to go away...
+	for (i = 0; i < num_gotos; )
+	{
+		if (pr_gotos[i].statementno >= newstatementcount)
+		{
+			memmove(&pr_gotos[i], &pr_gotos[i+1], sizeof(*pr_gotos)*(num_gotos-(i+1)));
+			num_gotos--;
+		}
+		else
+			i++;
+	}
+	for (i = 0; i < num_labels; )
+	{	//FIXME: stripping a label? erk?
+		if (pr_labels[i].statementno >= newstatementcount)
+		{
+			memmove(&pr_labels[i], &pr_labels[i+1], sizeof(*pr_labels)*(num_labels-(i+1)));
+			num_labels--;
+		}
+		else
+			i++;
+	}
+	for (i = 0; i < num_breaks; )
+	{
+		if (pr_breaks[i] >= newstatementcount)
+		{
+			memmove(&pr_breaks[i], &pr_breaks[i+1], sizeof(*pr_breaks)*(num_breaks-(i+1)));
+			num_breaks--;
+		}
+		else
+			i++;
+	}
+	for (i = 0; i < num_continues; )
+	{
+		if (pr_continues[i] >= newstatementcount)
+		{
+			memmove(&pr_continues[i], &pr_continues[i+1], sizeof(*pr_continues)*(num_continues-(i+1)));
+			num_continues--;
+		}
+		else
+			i++;
+	}
+	for (i = 0; i < num_cases; )
+	{
+		if (pr_cases[i] >= newstatementcount)
+		{
+			memmove(&pr_cases[i], &pr_cases[i+1], sizeof(*pr_cases)*(num_cases-(i+1)));
+			memmove(&pr_casesref[i], &pr_casesref[i+1], sizeof(*pr_casesref)*(num_cases-(i+1)));
+			memmove(&pr_casesref2[i], &pr_casesref2[i+1], sizeof(*pr_casesref2)*(num_cases-(i+1)));
+			num_cases--;
+		}
+		else
+			i++;
+	}
+
+	numstatements = newstatementcount;
+}
+
 /*
 ============
 PR_ParseImmediate
@@ -5363,7 +5427,7 @@ static QCC_sref_t QCC_PR_Inline(QCC_sref_t fdef, QCC_ref_t **arglist, unsigned i
 	}
 
 	if (!ctx.result.cast)
-		numstatements = statements;	//on failure, remove the extra statements
+		QCC_UngenerateStatements(statements);
 	else
 	{	//on success, make sure the args were freed
 		while (argcount-->0)
@@ -11071,7 +11135,7 @@ void QCC_PR_ParseStatement (void)
 		QCC_PR_ParseStatement ();
 		if (striptruth && oldlab == num_labels)
 		{
-			numstatements = oldnumst;
+			QCC_UngenerateStatements(oldnumst);
 			patch1 = NULL;
 		}
 		else
@@ -11096,7 +11160,7 @@ void QCC_PR_ParseStatement (void)
 				if (stripfalse && oldlab == num_labels)
 				{
 					patch2 = NULL;
-					numstatements = oldnumst;
+					QCC_UngenerateStatements(oldnumst);
 
 					if (patch1)
 						patch1->b.ofs = &statements[numstatements] - patch1;
@@ -11118,7 +11182,7 @@ void QCC_PR_ParseStatement (void)
 				if (stripfalse && oldlab == num_labels)
 				{
 					patch2 = NULL;
-					numstatements = oldnumst;
+					QCC_UngenerateStatements(oldnumst);
 
 					if (patch1)
 						patch1->b.ofs = &statements[numstatements] - patch1;
@@ -13231,7 +13295,7 @@ QCC_function_t *QCC_PR_ParseImmediateStatements (QCC_def_t *def, QCC_type_t *typ
 	{	//FIXME: should probably always take this path, but kinda pointless until we have relocs for defs
 		QCC_RemapLockedTemps(f->code, numstatements);
 		QCC_Marshal_Locals(f->code, numstatements);
-		QCC_WriteAsmFunction(f, f->code, f->firstlocal);	//FIXME: this will print the entire function, not just the part that we added. and we'll print it all again later, too. should probably make it a function attribute that we check at the end.
+//		QCC_WriteAsmFunction(f, f->code, f->firstlocal);	//FIXME: this will print the entire function, not just the part that we added. and we'll print it all again later, too. should probably make it a function attribute that we check at the end.
 
 		f->numstatements = numstatements - f->code;
 		f->statements = qccHunkAlloc(sizeof(*statements)*f->numstatements);
diff --git a/engine/qclib/qccguiqt.cpp b/engine/qclib/qccguiqt.cpp
index c79c54b29..266955e69 100644
--- a/engine/qclib/qccguiqt.cpp
+++ b/engine/qclib/qccguiqt.cpp
@@ -395,6 +395,7 @@ public:
 		if (c)
 			return;	//already in there.
 
+		beginResetModel();
 		c = new filenode_s();
 		c->name = strdup(filename);
 		c->parent = p;
@@ -402,6 +403,7 @@ public:
 		p->children = cpprealloc(p->children, sizeof(*p->children)*(p->numchildren+1));
 		p->children[p->numchildren] = c;
 		p->numchildren++;
+		endResetModel();
 	}
 };
 
@@ -925,6 +927,29 @@ public:
 		return ret;
 	}
 
+	bool annotate(const char *line)
+	{
+		auto filename = line+6;
+		auto filenameend = strchr(filename, ':');
+		if (!filenameend) return false;
+		auto linenum = atoi(filenameend+1);
+		line = strchr(filenameend+1, ':')+1;
+		if (!line) return false;
+		if (strncmp(curdoc->fname, filename, filenameend-filename) || curdoc->fname[filenameend-filename])
+		{
+			auto d = FindFile(filename);
+			if (d)
+			{
+				curdoc = d;
+				s->setDocument(d->doc);
+			}
+			else
+				return false;	//some other file that we're not interested in
+		}
+
+		s->annotate(linenum-1, s->annotation(linenum) + line + "\n", 0);
+		return true;
+	}
 
 	bool saveDocument(document_s *d)
 	{
@@ -1848,7 +1873,12 @@ int GUIprintf(const char *msg, ...)
 			QString s = l.mid(0, idx);
 			l = l.mid(idx+1);
 
-			if (s.contains(": error") || s.contains(": werror") || !s.mid(0,5).compare("error", Qt::CaseInsensitive))
+			if (!s.mid(0, 6).compare("code: "))
+			{
+				mainwnd->docs.annotate(s.toUtf8().data());
+				continue;
+			}
+			else if (s.contains(": error") || s.contains(": werror") || !s.mid(0,5).compare("error", Qt::CaseInsensitive))
 				mainwnd->log.setTextColor(QColor(255, 0, 0));
 			else if (s.contains(": warning"))
 				mainwnd->log.setTextColor(QColor(128, 128, 0));
@@ -1892,7 +1922,6 @@ void documentlist::EditFile(document_s *c, const char *filename, int linenum, bo
 		if (!CreateDocument(c))
 		{
 			delete(c);
-			numdocuments--;
 			return;
 		}