mirror of
https://github.com/ultimatepp/ultimatepp.git
synced 2026-05-15 14:16:07 -06:00
215 lines
5.1 KiB
C++
215 lines
5.1 KiB
C++
#include "ide.h"
|
|
|
|
#if 0
|
|
#define LDUMP(x) DDUMP(x)
|
|
#define LDUMPC(x) DDUMPC(x)
|
|
#define LLOG(x) DLOG(x)
|
|
#else
|
|
#define LDUMP(x)
|
|
#define LDUMPC(x)
|
|
#define LLOG(x)
|
|
#endif
|
|
|
|
bool AssistEditor::WaitCurrentFile()
|
|
{
|
|
if(!HasLibClang())
|
|
return false;
|
|
if(annotating) {
|
|
if(!IsCurrentFileParsing())
|
|
SyncCurrentFile();
|
|
Progress pi("Parsing");
|
|
while(annotating)
|
|
if(pi.StepCanceled())
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void AssistEditor::DCopy()
|
|
{ // changes declaration <-> definition
|
|
String r;
|
|
int l, h;
|
|
if(!GetSelection32(l, h))
|
|
l = h = GetCursor();
|
|
|
|
int first_line = GetLine(l);
|
|
int last_line = GetLine(h);
|
|
|
|
if(last_line - first_line > 10000) {
|
|
Exclamation("Too many lines.");
|
|
return;
|
|
}
|
|
|
|
if(!WaitCurrentFile())
|
|
return;
|
|
|
|
String result;
|
|
|
|
for(const AnnotationItem& m : annotations) {
|
|
if(first_line <= m.pos.y && m.pos.y <= last_line) {
|
|
String cls = GetClass(m);
|
|
if(IsFunction(m.kind)) {
|
|
String text;
|
|
for(int i = m.pos.y; i < GetLineCount(); i++) {
|
|
String l = GetUtf8Line(i);
|
|
int q = max(l.ReverseFind(';'), l.ReverseFind('{'));
|
|
if(q >= 0)
|
|
l.Trim(q);
|
|
text << l << ' ';
|
|
if(q >= 0)
|
|
break;
|
|
}
|
|
|
|
const char *fn_name_pos = nullptr;
|
|
const char *fn_params_pos = nullptr;
|
|
const char *id_pos = nullptr;
|
|
|
|
int lvl = 0;
|
|
CParser p(text);
|
|
try {
|
|
while(!p.IsEof()) {
|
|
const char *ptr = p.GetPtr();
|
|
if(p.Char('(')) {
|
|
if(lvl == 0) {
|
|
fn_params_pos = ptr;
|
|
fn_name_pos = id_pos;
|
|
}
|
|
lvl++;
|
|
}
|
|
else
|
|
if(p.Char(')'))
|
|
lvl--;
|
|
else
|
|
if(p.IsId()) {
|
|
id_pos = p.GetPtr();
|
|
do
|
|
p.ReadId();
|
|
while(p.Char2(':', ':') && p.IsId());
|
|
}
|
|
else {
|
|
id_pos = nullptr;
|
|
p.Skip();
|
|
}
|
|
}
|
|
}
|
|
catch(CParser::Error) {}
|
|
|
|
String ret, name, params;
|
|
if(fn_params_pos) {
|
|
params = fn_params_pos;
|
|
if(fn_name_pos) {
|
|
name = String(fn_name_pos, fn_params_pos);
|
|
ret = String(text, fn_name_pos);
|
|
}
|
|
}
|
|
|
|
auto Clean = [](String& s) {
|
|
s = NormalizeSpaces((TrimBoth(Filter(s, [](int c) { return c < 32 ? 32 : c; }))));
|
|
};
|
|
|
|
Clean(ret);
|
|
Clean(name);
|
|
Clean(params);
|
|
|
|
if(ret.GetCount() && name.GetCount() && params.GetCount()) { // prefer original text
|
|
if(m.definition) {
|
|
if(IsMethod(m.kind))
|
|
result << '\t';
|
|
result << ret << ' ' << m.name << params << ";\n";
|
|
}
|
|
else {
|
|
ret.TrimStart("virtual ");
|
|
ret.TrimStart("static ");
|
|
ret.TrimStart("friend ");
|
|
params.TrimEnd("override");
|
|
params = TrimBoth(params);
|
|
String cret;
|
|
if(IsMethod(m.kind)) { // attempt to qualify local classes in return value type
|
|
bool qualified = false;
|
|
const char *begin = ret;
|
|
String st = m.nest + "::";
|
|
VectorMap<String, String> qname;
|
|
for(const AnnotationItem& am : annotations) {
|
|
if(IsStruct(am.kind) && am.nest.StartsWith(st))
|
|
qname.Add(am.name, am.nest);
|
|
if(IsTypedef(am.kind) && am.nest == m.nest)
|
|
qname.Add(am.name, am.nest + "::" + am.name);
|
|
}
|
|
try {
|
|
CParser p(ret);
|
|
while(!p.IsEof()) {
|
|
if(p.Char2(':', ':'))
|
|
qualified = true;
|
|
else
|
|
if(p.IsId() && !qualified) {
|
|
const char *q = p.GetPtr();
|
|
String id = p.ReadId();
|
|
if(p.Char2(':', ':'))
|
|
qualified = true;
|
|
else
|
|
if(!p.IsId() && qname.Find(id) >= 0) {
|
|
cret.Cat(begin, q);
|
|
begin = p.GetPtr();
|
|
cret << qname.Get(id, id);
|
|
}
|
|
}
|
|
else {
|
|
qualified = false;
|
|
p.Skip();
|
|
}
|
|
}
|
|
}
|
|
catch(CParser::Error) {}
|
|
cret.Cat(begin, ret.End());
|
|
}
|
|
else
|
|
cret = ret;
|
|
result << cret << ' ' << cls << m.name << params << "\n{\n}\n\n";
|
|
}
|
|
}
|
|
else { // just in case our heuristics split of original text failed
|
|
if(m.definition) {
|
|
if(cls.GetCount())
|
|
result << '\t';
|
|
result << m.pretty << ";\n";
|
|
}
|
|
else
|
|
result << MakeDefinition(m);
|
|
}
|
|
}
|
|
if(m.kind == CXCursor_VarDecl) {
|
|
if(cls.GetCount()) { // class variable
|
|
if(m.definition) {
|
|
int q = FindId(m.pretty, m.name);
|
|
if(q >= 0) {
|
|
int w = m.pretty.ReverseFind(' ', q);
|
|
if(w >= 0)
|
|
result << "\tstatic " << m.pretty.Mid(0, w + 1) << m.pretty.Mid(q) << ";\n";
|
|
}
|
|
}
|
|
else {
|
|
String h = m.pretty;
|
|
h.TrimStart("static ");
|
|
h = TrimLeft(h);
|
|
int q = FindId(h, m.name);
|
|
if(q >= 0)
|
|
result << h.Mid(0, q) << cls << h.Mid(q) << ";\n";
|
|
}
|
|
}
|
|
else { // just toggle extern
|
|
String h = m.pretty;
|
|
if(FindId(GetUtf8Line(m.pos.y), "extern") < 0)
|
|
h = "extern " + h;
|
|
result << h << ";\n";
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if(result.GetCount() == 0) {
|
|
PromptOK("No relevant declarations found.");
|
|
return;
|
|
}
|
|
|
|
WriteClipboardText(result);
|
|
}
|