gtk+-4.0: Update to 3.90.0
[vala-gnome.git] / vala / valareport.vala
blobf977dce036fb6b351c8940f86d3c8f8e633b3011
1 /* valareport.vala
3 * Copyright (C) 2006-2010 Jürg Billeter
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 * Author:
20 * Jürg Billeter <j@bitron.ch>
23 using GLib;
26 /**
27 * Namespace to centralize reporting warnings and errors.
29 public class Vala.Report : Object {
30 /**
31 * SGR end tag
33 private const string ANSI_COLOR_END = "\x1b[0m";
35 /**
36 * SGR start tag for source location
38 private string locus_color_start = "";
40 /**
41 * SGR end tag for source location
43 private unowned string locus_color_end = "";
45 /**
46 * SGR start tag for warning titles
48 private string warning_color_start = "";
50 /**
51 * SGR end tag for warning titles
53 private unowned string warning_color_end = "";
55 /**
56 * SGR start tag for error titles
58 private string error_color_start = "";
60 /**
61 * SGR end tag for error titles
63 private unowned string error_color_end = "";
65 /**
66 * SGR start tag for note titles
68 private string note_color_start = "";
70 /**
71 * SGR end tag for note titles
73 private unowned string note_color_end = "";
75 /**
76 * SGR start tag for caret line (^^^)
78 private string caret_color_start = "";
80 /**
81 * SGR end tag for caret line (^^^)
83 private unowned string caret_color_end = "";
85 /**
86 * SGR start tag for quotes line ('', ``, `')
88 private string quote_color_start = "";
90 /**
91 * SGR end tag for quotes line ('', ``, `')
93 private unowned string quote_color_end = "";
96 protected int warnings;
97 protected int errors;
99 private bool verbose_errors;
101 public bool enable_warnings { get; set; default = true; }
103 static GLib.Regex val_regex;
106 * Set all colors by string
108 * {{{
109 * "error=01;31:warning=01;35:note=01;36:caret=01;32:locus=01:quote=01"
110 * }}}
112 public bool set_colors (string str) {
113 try {
114 if (val_regex == null)
115 val_regex = new Regex ("^\\s*[0-9]+(;[0-9]*)*\\s*$");
116 } catch (RegexError e) {
117 assert_not_reached ();
120 string error_color = null;
121 string warning_color = null;
122 string note_color = null;
123 string caret_color = null;
124 string locus_color = null;
125 string quote_color = null;
127 string[] fragments = str.split (":");
128 foreach (unowned string fragment in fragments) {
129 string[] eq = fragment.split ("=", 2);
130 if (eq.length != 2) {
131 return false;
134 if (!val_regex.match (eq[1])) {
135 return false;
139 unowned string checked_value = eq[1]._strip ();
140 switch (eq[0]._strip ()) {
141 case "error":
142 error_color = checked_value;
143 break;
145 case "warning":
146 warning_color = checked_value;
147 break;
149 case "note":
150 note_color = checked_value;
151 break;
153 case "caret":
154 caret_color = checked_value;
155 break;
157 case "locus":
158 locus_color = checked_value;
159 break;
161 case "quote":
162 quote_color = checked_value;
163 break;
165 default:
166 return false;
170 if (is_atty (stderr.fileno ())) {
171 if (error_color != null) {
172 this.error_color_start = "\x1b[0" + error_color + "m";
173 this.error_color_end = ANSI_COLOR_END;
176 if (warning_color != null) {
177 this.warning_color_start = "\x1b[0" + warning_color + "m";
178 this.warning_color_end = ANSI_COLOR_END;
181 if (note_color != null) {
182 this.note_color_start = "\x1b[0" + note_color + "m";
183 this.note_color_end = ANSI_COLOR_END;
186 if (caret_color != null) {
187 this.caret_color_start = "\x1b[0" + caret_color + "m";
188 this.caret_color_end = ANSI_COLOR_END;
191 if (locus_color != null) {
192 this.locus_color_start = "\x1b[0" + locus_color + "m";
193 this.locus_color_end = ANSI_COLOR_END;
196 if (quote_color != null) {
197 this.quote_color_start = "\x1b[0" + quote_color + "m";
198 this.quote_color_end = ANSI_COLOR_END;
201 return true;
205 * Set the error verbosity.
207 public void set_verbose_errors (bool verbose) {
208 verbose_errors = verbose;
212 * Returns the total number of warnings reported.
214 public int get_warnings () {
215 return warnings;
219 * Returns the total number of errors reported.
221 public int get_errors () {
222 return errors;
226 * Pretty-print the actual line of offending code if possible.
228 private void report_source (SourceReference source) {
229 if (source.begin.line != source.end.line) {
230 // FIXME Cannot report multi-line issues currently
231 return;
234 string offending_line = source.file.get_source_line (source.begin.line);
236 if (offending_line != null) {
237 stderr.printf ("%s\n", offending_line);
238 int idx;
240 /* We loop in this manner so that we don't fall over on differing
241 * tab widths. This means we get the ^s in the right places.
243 for (idx = 1; idx < source.begin.column; ++idx) {
244 if (offending_line[idx - 1] == '\t') {
245 stderr.printf ("\t");
246 } else {
247 stderr.printf (" ");
251 stderr.puts (caret_color_start);
252 for (idx = source.begin.column; idx <= source.end.column; ++idx) {
253 if (offending_line[idx - 1] == '\t') {
254 stderr.printf ("\t");
255 } else {
256 stderr.printf ("^");
259 stderr.puts (caret_color_end);
261 stderr.printf ("\n");
265 private void print_highlighted_message (string message) {
266 int start = 0;
267 int cur = 0;
269 while (message[cur] != '\0') {
270 if (message[cur] == '\'' || message[cur] == '`') {
271 unowned string end_chars = (message[cur] == '`')? "`'" : "'";
272 stderr.puts (message.substring (start, cur - start));
273 start = cur;
274 cur++;
276 while (message[cur] != '\0' && end_chars.index_of_char (message[cur]) < 0) {
277 cur++;
279 if (message[cur] == '\0') {
280 stderr.puts (message.substring (start, cur - start));
281 start = cur;
282 } else {
283 cur++;
284 stderr.printf ("%s%s%s", quote_color_start, message.substring (start, cur - start), quote_color_end);
285 start = cur;
287 } else {
288 cur++;
292 stderr.puts (message.offset (start));
295 private void print_message (SourceReference? source, string type, string type_color_start, string type_color_end, string message, bool do_report_source) {
296 if (source != null) {
297 stderr.printf ("%s%s:%s ", locus_color_start, source.to_string (), locus_color_end);
300 stderr.printf ("%s%s:%s ", type_color_start, type, type_color_end);
302 // highlight '', `', ``
303 print_highlighted_message (message);
304 stderr.putc ('\n');
306 if (do_report_source && source != null) {
307 report_source (source);
312 * Reports the specified message as note.
314 * @param source reference to source code
315 * @param message note message
317 public virtual void note (SourceReference? source, string message) {
318 if (!enable_warnings) {
319 return;
322 print_message (source, "note", note_color_start, note_color_end, message, verbose_errors);
326 * Reports the specified message as deprecation warning.
328 * @param source reference to source code
329 * @param message warning message
331 public virtual void depr (SourceReference? source, string message) {
332 if (!enable_warnings) {
333 return;
336 warnings++;
338 print_message (source, "warning", warning_color_start, warning_color_end, message, false);
342 * Reports the specified message as warning.
344 * @param source reference to source code
345 * @param message warning message
347 public virtual void warn (SourceReference? source, string message) {
348 if (!enable_warnings) {
349 return;
352 warnings++;
354 print_message (source, "warning", warning_color_start, warning_color_end, message, verbose_errors);
358 * Reports the specified message as error.
360 * @param source reference to source code
361 * @param message error message
363 public virtual void err (SourceReference? source, string message) {
364 errors++;
366 print_message (source, "error", error_color_start, error_color_end, message, verbose_errors);
369 /* Convenience methods calling warn and err on correct instance */
370 public static void notice (SourceReference? source, string message) {
371 CodeContext.get ().report.note (source, message);
373 public static void deprecated (SourceReference? source, string message) {
374 CodeContext.get ().report.depr (source, message);
376 public static void experimental (SourceReference? source, string message) {
377 CodeContext.get ().report.depr (source, message);
379 public static void warning (SourceReference? source, string message) {
380 CodeContext.get ().report.warn (source, message);
382 public static void error (SourceReference? source, string message) {
383 CodeContext.get ().report.err (source, message);
387 [CCode (has_target = false)]
388 private delegate int AttyFunc (int fd);
390 private bool is_atty (int fd) {
391 Module module = Module.open (null, ModuleFlags.BIND_LAZY);
392 if (module == null) {
393 return false;
396 void* _func;
397 module.symbol ("isatty", out _func);
398 if (_func == null) {
399 return false;
402 AttyFunc? func = (AttyFunc) _func;
403 return func (fd) == 1;