1
|
#include "ide.h"
|
2
|
|
3
|
bool Ide::FindLineError(const String& ln, FindLineErrorCache& cache, ErrorInfo& f)
|
4
|
{
|
5
|
VectorMap<String, String> bm = GetMethodVars(method);
|
6
|
bool is_java = (bm.Get("BUILDER", Null) == "JDK");
|
7
|
const char *s = ln;
|
8
|
while(*s == ' ' || *s == '\t')
|
9
|
s++;
|
10
|
for(; s < ln.End(); s++) {
|
11
|
if(*s != '\"' && (byte)*s >= 32 && *s != '(' && (f.file.GetLength() < 3 || *s != ':'))
|
12
|
f.file.Cat(*s);
|
13
|
else {
|
14
|
if(*s == '\"') {
|
15
|
f.file = Null;
|
16
|
s++;
|
17
|
while(*s && *s != '\"')
|
18
|
f.file.Cat(*s++);
|
19
|
if(*s)
|
20
|
s++;
|
21
|
}
|
22
|
int e = f.file.GetLength();
|
23
|
while(e > 0 && f.file[e - 1] == ' ')
|
24
|
e--;
|
25
|
f.file.Trim(e);
|
26
|
f.file = TrimLeft(f.file);
|
27
|
String upp = GetUppDir();
|
28
|
#ifdef PLATFORM_WIN32
|
29
|
if(f.file[0] == '\\' || f.file[0] == '/')
|
30
|
f.file = String(upp[0], 1) + ':' + f.file;
|
31
|
#endif
|
32
|
if(!IsFullPath(f.file) && *f.file != '\\' && *f.file != '/') {
|
33
|
if(cache.wspc_paths.IsEmpty()) {
|
34
|
::Workspace wspc;
|
35
|
wspc.Scan(main);
|
36
|
for(int i = 0; i < wspc.GetCount(); i++)
|
37
|
cache.wspc_paths.Add(GetFileDirectory(PackagePath(wspc[i])));
|
38
|
}
|
39
|
for(int i = 0; i < cache.wspc_paths.GetCount(); i++) {
|
40
|
String path = AppendFileName(cache.wspc_paths[i], f.file);
|
41
|
int q = cache.ff.Find(path);
|
42
|
if(q >= 0) {
|
43
|
if(cache.ff[q]) {
|
44
|
f.file = path;
|
45
|
break;
|
46
|
}
|
47
|
}
|
48
|
else {
|
49
|
bool b = false;
|
50
|
String ext = ToLower(GetFileExt(path));
|
51
|
if(findarg(ext, ".obj", ".lib", ".o", ".so", ".a", ".", "") < 0) {
|
52
|
FindFile ff;
|
53
|
b = ff.Search(path) && ff.IsFile();
|
54
|
}
|
55
|
cache.ff.Add(path, b);
|
56
|
if(b) {
|
57
|
f.file = path;
|
58
|
break;
|
59
|
}
|
60
|
}
|
61
|
}
|
62
|
}
|
63
|
f.file = FollowCygwinSymlink(f.file);
|
64
|
if(IsFullPath(f.file) && FileExists(f.file) && IsTextFile(f.file)) {
|
65
|
while(*s && !IsDigit(*s))
|
66
|
s++;
|
67
|
f.lineno = f.linepos = 0;
|
68
|
CParser p(s);
|
69
|
if(p.IsInt())
|
70
|
f.lineno = p.ReadInt();
|
71
|
if(p.Char(':') && p.IsInt())
|
72
|
f.linepos = p.ReadInt();
|
73
|
const char *ms = p.GetPtr();
|
74
|
int pos = ms - ~ln;
|
75
|
f.kind = ln.Find("error", pos) > 0 ? 1 :
|
76
|
ln.Find("warning", pos) > 0 ? 2 :
|
77
|
ln.Find("note", pos) > 0 ? 3 : 4;
|
78
|
const char *hs = ms;
|
79
|
while(!IsLetter(*hs) && *hs)
|
80
|
hs++;
|
81
|
f.message = *hs ? hs : ms;
|
82
|
f.message = TrimLeft(f.message);
|
83
|
Vector<String> conf = SplitFlags(mainconfigparam, true);
|
84
|
String uppout = GetVar("OUTPUT");
|
85
|
int upplen = uppout.GetLength();
|
86
|
if(is_java && f.file.GetLength() > upplen
|
87
|
&& !MemICmp(f.file, uppout, upplen) && f.file[upplen] == DIR_SEP) {
|
88
|
FileIn fi(f.file);
|
89
|
if(fi.IsOpen())
|
90
|
{
|
91
|
String fake_file = f.file;
|
92
|
int fake_line = 1;
|
93
|
int file_line = 1;
|
94
|
while(!fi.IsEof())
|
95
|
{
|
96
|
String line = fi.GetLine();
|
97
|
const char *p = line;
|
98
|
if(p[0] == '/' && p[1] == '/' && p[2] == '#')
|
99
|
{
|
100
|
p += 3;
|
101
|
if(p[0] == 'l' && p[1] == 'i' && p[2] == 'n' && p[3] == 'e')
|
102
|
p += 4;
|
103
|
while(*p == ' ' || *p == '\t')
|
104
|
p++;
|
105
|
if(IsDigit(*p))
|
106
|
{
|
107
|
fake_line = stou(p, &p);
|
108
|
while(*p == ' ' || *p == '\t')
|
109
|
p++;
|
110
|
if(*p == '\"')
|
111
|
p++;
|
112
|
fake_file.Clear();
|
113
|
while(*p && *p != '\"')
|
114
|
if(*p == '/')
|
115
|
{
|
116
|
fake_file.Cat('/');
|
117
|
if(p[1] == '/')
|
118
|
p++;
|
119
|
p++;
|
120
|
}
|
121
|
else
|
122
|
fake_file.Cat(*p++);
|
123
|
}
|
124
|
file_line++;
|
125
|
continue;
|
126
|
}
|
127
|
if(f.lineno <= file_line) {
|
128
|
f.file = fake_file;
|
129
|
f.lineno = fake_line;
|
130
|
f.linepos = 0;
|
131
|
break;
|
132
|
}
|
133
|
file_line++;
|
134
|
fake_line++;
|
135
|
}
|
136
|
}
|
137
|
}
|
138
|
if(f.lineno > 0)
|
139
|
return true;
|
140
|
}
|
141
|
f.file.Clear();
|
142
|
}
|
143
|
}
|
144
|
return false;
|
145
|
}
|
146
|
|
147
|
void Ide::FindError()
|
148
|
{
|
149
|
FindLineError(console.GetLine(console.GetCursor()));
|
150
|
}
|
151
|
|
152
|
bool Ide::Next(int tab, ArrayCtrl& a, int d)
|
153
|
{
|
154
|
if(btabs.GetCursor() == tab) {
|
155
|
int c = a.GetCursor() + d;
|
156
|
if(c >= 0 && c < a.GetCount())
|
157
|
a.SetCursor(c);
|
158
|
else {
|
159
|
if(d > 0)
|
160
|
a.GoBegin();
|
161
|
else
|
162
|
a.GoEnd();
|
163
|
}
|
164
|
return true;
|
165
|
}
|
166
|
return false;
|
167
|
}
|
168
|
|
169
|
void Ide::FindNextError()
|
170
|
{
|
171
|
if(Next(BCONSOLE, error, 1) || Next(BFINDINFILES, ffound, 1))
|
172
|
return;
|
173
|
int ln = console.GetLine(console.GetCursor());
|
174
|
int l = ln;
|
175
|
for(l = ln; l < console.GetLineCount(); l++)
|
176
|
if(FindLineError(l)) return;
|
177
|
for(l = 0; l < ln; l++)
|
178
|
if(FindLineError(l)) return;
|
179
|
}
|
180
|
|
181
|
void Ide::FindPrevError() {
|
182
|
if(Next(BCONSOLE, error, -1) || Next(BFINDINFILES, ffound, -1))
|
183
|
return;
|
184
|
int ln = console.GetLine(console.GetCursor());
|
185
|
int l = ln;
|
186
|
One<Host> host = CreateHost(false);
|
187
|
for(l = ln - 2; l >= 0; l--)
|
188
|
if(FindLineError(l)) return;
|
189
|
for(l = console.GetLineCount() - 1; l > ln; l--)
|
190
|
if(FindLineError(l)) return;
|
191
|
}
|
192
|
|
193
|
void Ide::ClearErrorEditor()
|
194
|
{
|
195
|
if(!mark_lines)
|
196
|
return;
|
197
|
|
198
|
for(int i = 0; i < filedata.GetCount(); i++) {
|
199
|
ClearErrorEditor(filedata.GetKey(i));
|
200
|
}
|
201
|
|
202
|
SetErrorFiles(Vector<String>());
|
203
|
}
|
204
|
|
205
|
void Ide::ClearErrorEditor(String file)
|
206
|
{
|
207
|
if(!mark_lines)
|
208
|
return;
|
209
|
if(file == editfile)
|
210
|
editor.ClearErrors();
|
211
|
else {
|
212
|
FileData& fd = Filedata(file);
|
213
|
ClearErrors(fd.lineinfo);
|
214
|
}
|
215
|
}
|
216
|
|
217
|
void Ide::SetErrorEditor()
|
218
|
{
|
219
|
if(error.GetCount()) {
|
220
|
SetBottom(BERRORS);
|
221
|
|
222
|
|
223
|
}
|
224
|
|
225
|
if(!mark_lines)
|
226
|
return;
|
227
|
|
228
|
bool refresh = false;
|
229
|
String hfile;
|
230
|
EditorBar hbar;
|
231
|
Vector<String> errorfiles;
|
232
|
FindLineErrorCache cache;
|
233
|
for(int i = 0; i < console.GetLineCount(); i++) {
|
234
|
ErrorInfo f;
|
235
|
if(FindLineError(console.GetUtf8Line(i), cache, f)) {
|
236
|
String file = NormalizePath(f.file);
|
237
|
#ifdef PLATFORM_WIN32
|
238
|
errorfiles.Add(ToLower(file));
|
239
|
#else
|
240
|
errorfiles.Add(file);
|
241
|
#endif
|
242
|
if(editfile == file) {
|
243
|
editor.SetError(f.lineno - 1, f.kind);
|
244
|
refresh = true;
|
245
|
}
|
246
|
else {
|
247
|
if(hfile != file) {
|
248
|
if(hfile.GetCount())
|
249
|
Filedata(hfile).lineinfo = hbar.GetLineInfo();
|
250
|
hbar.SetLineInfo(Filedata(file).lineinfo, -1);
|
251
|
hfile = file;
|
252
|
}
|
253
|
hbar.SetError(f.lineno - 1, f.kind);
|
254
|
}
|
255
|
}
|
256
|
}
|
257
|
if(hfile.GetCount())
|
258
|
Filedata(hfile).lineinfo = hbar.GetLineInfo();
|
259
|
if(refresh)
|
260
|
editor.RefreshFrame();
|
261
|
SetErrorFiles(errorfiles);
|
262
|
}
|
263
|
|
264
|
void Ide::GoToError(const ErrorInfo& f)
|
265
|
{
|
266
|
if(IsNull(f.file))
|
267
|
return;
|
268
|
String file = NormalizePath(f.file);
|
269
|
editastext.FindAdd(file);
|
270
|
EditFile(file);
|
271
|
editor.SetCursor(editor.GetPos(editor.GetLineNo(f.lineno - 1), max(f.linepos - 1, 0)));
|
272
|
editor.CenterCursor();
|
273
|
editor.SetFocus();
|
274
|
Sync();
|
275
|
}
|
276
|
|
277
|
bool Ide::FindLineError(int l) {
|
278
|
ErrorInfo f;
|
279
|
FindLineErrorCache cache;
|
280
|
if(FindLineError(console.GetUtf8Line(l), cache, f)) {
|
281
|
GoToError(f);
|
282
|
console.SetSelection(console.GetPos(l), console.GetPos(l + 1));
|
283
|
if(btabs.GetCursor() != BCONSOLE && btabs.GetCursor() != BFINDINFILES)
|
284
|
ShowConsole();
|
285
|
return true;
|
286
|
}
|
287
|
return false;
|
288
|
}
|
289
|
|
290
|
void Ide::ConsoleLine(const String& line)
|
291
|
{
|
292
|
ErrorInfo f;
|
293
|
if(FindLineError(line, error_cache, f)) {
|
294
|
if(findarg(f.kind, 1, 2) >= 0 || error.GetCount() == 0) {
|
295
|
error.Add(GetFileName(f.file), f.lineno,
|
296
|
AttrText(f.message)
|
297
|
.NormalPaper(HighlightSetup::GetHlStyle(f.kind == 1 ? HighlightSetup::PAPER_ERROR
|
298
|
: HighlightSetup::PAPER_WARNING).color),
|
299
|
RawToValue(f));
|
300
|
return;
|
301
|
}
|
302
|
}
|
303
|
else {
|
304
|
f.lineno = Null;
|
305
|
f.file = Null;
|
306
|
f.message = TrimLeft(line);
|
307
|
}
|
308
|
AddNote(f);
|
309
|
}
|
310
|
|
311
|
void Ide::AddNote(const ErrorInfo& f)
|
312
|
{
|
313
|
int cnt = error.GetCount();
|
314
|
if(cnt == 0)
|
315
|
return;
|
316
|
ValueArray n = error.Get(cnt - 1, "NOTES");
|
317
|
n.Add(RawToValue(f));
|
318
|
error.Set(cnt - 1, "NOTES", n);
|
319
|
}
|
320
|
|
321
|
void Ide::ShowNote()
|
322
|
{
|
323
|
if(notes.IsCursor())
|
324
|
GoToError(ValueTo<ErrorInfo>(notes.Get("INFO")));
|
325
|
}
|
326
|
|
327
|
void Ide::ShowFound()
|
328
|
{
|
329
|
if(ffound.IsCursor() && ffound.GetCursor() < ffound.GetCount() - 1)
|
330
|
GoToError(ValueTo<ErrorInfo>(ffound.Get("INFO")));
|
331
|
}
|
332
|
|
333
|
void Ide::ShowError()
|
334
|
{
|
335
|
notes.Clear();
|
336
|
if(error.IsCursor()) {
|
337
|
ValueArray n = error.Get("NOTES");
|
338
|
for(int i = 0; i < n.GetCount(); i++) {
|
339
|
const ErrorInfo& f = ValueTo<ErrorInfo>(n[i]);
|
340
|
notes.Add(GetFileName(f.file), f.lineno, f.message, n[i]);
|
341
|
}
|
342
|
GoToError(ValueTo<ErrorInfo>(error.Get("INFO")));
|
343
|
}
|
344
|
}
|
345
|
|
346
|
void Ide::FoundDisplay::Paint(Draw& w, const Rect& r, const Value& q, Color ink, Color paper, dword style) const
|
347
|
{
|
348
|
String s = q;
|
349
|
if(*s == '\1') {
|
350
|
Vector<String> h = Split(s, '\1');
|
351
|
if(h.GetCount() < 4)
|
352
|
return;
|
353
|
One<EditorSyntax> es = EditorSyntax::Create(h[0]);
|
354
|
es->IgnoreErrors();
|
355
|
WString ln = h[3].ToWString();
|
356
|
Vector<LineEdit::Highlight> hln;
|
357
|
hln.SetCount(ln.GetCount() + 1);
|
358
|
for(int i = 0; i < ln.GetCount(); i++) {
|
359
|
LineEdit::Highlight& h = hln[i];
|
360
|
h.paper = paper;
|
361
|
h.ink = SColorText();
|
362
|
h.chr = ln[i];
|
363
|
h.font = StdFont();
|
364
|
}
|
365
|
HighlightOutput hl(hln);
|
366
|
es->Highlight(ln.Begin(), ln.End(), hl, NULL, 0, 0);
|
367
|
int fcy = GetStdFontCy();
|
368
|
int y = r.top + (r.GetHeight() - fcy) / 2;
|
369
|
int x = r.left;
|
370
|
w.DrawRect(r, paper);
|
371
|
int sl = utf8len(~h[3], atoi(h[1]));
|
372
|
int sh = utf8len(~h[3] + sl, atoi(h[2])) + sl;
|
373
|
for(int i = 0; i < hln.GetCount(); i++) {
|
374
|
Font fnt = StdFont();
|
375
|
LineEdit::Highlight& h = hln[i];
|
376
|
fnt.Bold(h.font.IsBold());
|
377
|
fnt.Italic(h.font.IsItalic());
|
378
|
fnt.Underline(h.font.IsUnderline());
|
379
|
int cw = fnt[h.chr];
|
380
|
if(h.chr == '\t')
|
381
|
cw = 4 * fnt[' '];
|
382
|
if(i >= sl && i < sh && !(style & (CURSOR|SELECT|READONLY)))
|
383
|
w.DrawRect(x, y, cw, fcy, HighlightSetup::GetHlStyle(HighlightSetup::PAPER_SELWORD).color);
|
384
|
if(h.chr != '\t')
|
385
|
w.DrawText(x, y, &h.chr, fnt, h.ink, 1);
|
386
|
x += cw;
|
387
|
}
|
388
|
}
|
389
|
else
|
390
|
StdDisplay().Paint(w, r, q, ink, paper, style);
|
391
|
}
|