diff options
Diffstat (limited to 'src/libutil/error.cc')
-rw-r--r-- | src/libutil/error.cc | 240 |
1 files changed, 85 insertions, 155 deletions
diff --git a/src/libutil/error.cc b/src/libutil/error.cc index 803a72953..0eea3455d 100644 --- a/src/libutil/error.cc +++ b/src/libutil/error.cc @@ -43,9 +43,9 @@ string showErrPos(const ErrPos & errPos) { if (errPos.line > 0) { if (errPos.column > 0) { - return fmt("(%1%:%2%)", errPos.line, errPos.column); + return fmt("%d:%d", errPos.line, errPos.column); } else { - return fmt("(%1%)", errPos.line); + return fmt("%d", errPos.line); } } else { @@ -61,36 +61,31 @@ std::optional<LinesOfCode> getCodeLines(const ErrPos & errPos) if (errPos.origin == foFile) { LinesOfCode loc; try { + // FIXME: when running as the daemon, make sure we don't + // open a file to which the client doesn't have access. AutoCloseFD fd = open(errPos.file.c_str(), O_RDONLY | O_CLOEXEC); - if (!fd) { - logError(SysError("opening file '%1%'", errPos.file).info()); - return std::nullopt; - } - else + if (!fd) return {}; + + // count the newlines. + int count = 0; + string line; + int pl = errPos.line - 1; + do { - // count the newlines. - int count = 0; - string line; - int pl = errPos.line - 1; - do - { - line = readLine(fd.get()); - ++count; - if (count < pl) - { - ; - } - else if (count == pl) { - loc.prevLineOfCode = line; - } else if (count == pl + 1) { - loc.errLineOfCode = line; - } else if (count == pl + 2) { - loc.nextLineOfCode = line; - break; - } - } while (true); - return loc; - } + line = readLine(fd.get()); + ++count; + if (count < pl) + ; + else if (count == pl) + loc.prevLineOfCode = line; + else if (count == pl + 1) + loc.errLineOfCode = line; + else if (count == pl + 2) { + loc.nextLineOfCode = line; + break; + } + } while (true); + return loc; } catch (EndOfFile & eof) { if (loc.errLineOfCode.has_value()) @@ -99,7 +94,6 @@ std::optional<LinesOfCode> getCodeLines(const ErrPos & errPos) return std::nullopt; } catch (std::exception & e) { - printError("error reading nix file: %s\n%s", errPos.file, e.what()); return std::nullopt; } } else { @@ -186,24 +180,20 @@ void printCodeLines(std::ostream & out, } } -void printAtPos(const string & prefix, const ErrPos & pos, std::ostream & out) +void printAtPos(const ErrPos & pos, std::ostream & out) { - if (pos) - { + if (pos) { switch (pos.origin) { case foFile: { - out << prefix << ANSI_BLUE << "at: " << ANSI_YELLOW << showErrPos(pos) << - ANSI_BLUE << " in file: " << ANSI_NORMAL << pos.file; + out << fmt(ANSI_BLUE "at " ANSI_YELLOW "%s:%s" ANSI_NORMAL ":", pos.file, showErrPos(pos)); break; } case foString: { - out << prefix << ANSI_BLUE << "at: " << ANSI_YELLOW << showErrPos(pos) << - ANSI_BLUE << " from string" << ANSI_NORMAL; + out << fmt(ANSI_BLUE "at " ANSI_YELLOW "«string»:%s" ANSI_NORMAL ":", showErrPos(pos)); break; } case foStdin: { - out << prefix << ANSI_BLUE << "at: " << ANSI_YELLOW << showErrPos(pos) << - ANSI_BLUE << " from stdin" << ANSI_NORMAL; + out << fmt(ANSI_BLUE "at " ANSI_YELLOW "«stdin»:%s" ANSI_NORMAL ":", showErrPos(pos)); break; } default: @@ -212,168 +202,108 @@ void printAtPos(const string & prefix, const ErrPos & pos, std::ostream & out) } } -std::ostream & showErrorInfo(std::ostream & out, const ErrorInfo & einfo, bool showTrace) +static std::string indent(std::string_view indentFirst, std::string_view indentRest, std::string_view s) { - auto errwidth = std::max<size_t>(getWindowSize().second, 20); - string prefix = ""; + std::string res; + bool first = true; + + while (!s.empty()) { + auto end = s.find('\n'); + if (!first) res += "\n"; + res += chomp(std::string(first ? indentFirst : indentRest) + std::string(s.substr(0, end))); + first = false; + if (end == s.npos) break; + s = s.substr(end + 1); + } - string levelString; + return res; +} + +std::ostream & showErrorInfo(std::ostream & out, const ErrorInfo & einfo, bool showTrace) +{ + std::string prefix; switch (einfo.level) { case Verbosity::lvlError: { - levelString = ANSI_RED; - levelString += "error:"; - levelString += ANSI_NORMAL; + prefix = ANSI_RED "error"; + break; + } + case Verbosity::lvlNotice: { + prefix = ANSI_RED "note"; break; } case Verbosity::lvlWarn: { - levelString = ANSI_YELLOW; - levelString += "warning:"; - levelString += ANSI_NORMAL; + prefix = ANSI_YELLOW "warning"; break; } case Verbosity::lvlInfo: { - levelString = ANSI_GREEN; - levelString += "info:"; - levelString += ANSI_NORMAL; + prefix = ANSI_GREEN "info"; break; } case Verbosity::lvlTalkative: { - levelString = ANSI_GREEN; - levelString += "talk:"; - levelString += ANSI_NORMAL; + prefix = ANSI_GREEN "talk"; break; } case Verbosity::lvlChatty: { - levelString = ANSI_GREEN; - levelString += "chat:"; - levelString += ANSI_NORMAL; + prefix = ANSI_GREEN "chat"; break; } case Verbosity::lvlVomit: { - levelString = ANSI_GREEN; - levelString += "vomit:"; - levelString += ANSI_NORMAL; + prefix = ANSI_GREEN "vomit"; break; } case Verbosity::lvlDebug: { - levelString = ANSI_YELLOW; - levelString += "debug:"; - levelString += ANSI_NORMAL; - break; - } - default: { - levelString = fmt("invalid error level: %1%", einfo.level); + prefix = ANSI_YELLOW "debug"; break; } + default: + assert(false); } - auto ndl = prefix.length() - + filterANSIEscapes(levelString, true).length() - + 7 - + einfo.name.length() - + einfo.programName.value_or("").length(); - auto dashwidth = std::max<int>(errwidth - ndl, 3); - - std::string dashes(dashwidth, '-'); - - // divider. - if (einfo.name != "") - out << fmt("%1%%2%" ANSI_BLUE " --- %3% %4% %5%" ANSI_NORMAL, - prefix, - levelString, - einfo.name, - dashes, - einfo.programName.value_or("")); + // FIXME: show the program name as part of the trace? + if (einfo.programName && einfo.programName != ErrorInfo::programName) + prefix += fmt(" [%s]:" ANSI_NORMAL " ", einfo.programName.value_or("")); else - out << fmt("%1%%2%" ANSI_BLUE " -----%3% %4%" ANSI_NORMAL, - prefix, - levelString, - dashes, - einfo.programName.value_or("")); - - bool nl = false; // intersperse newline between sections. - if (einfo.errPos.has_value() && (*einfo.errPos)) { - out << prefix << std::endl; - printAtPos(prefix, *einfo.errPos, out); - nl = true; - } + prefix += ":" ANSI_NORMAL " "; - // description - if (einfo.description != "") { - if (nl) - out << std::endl << prefix; - out << std::endl << prefix << einfo.description; - nl = true; - } + std::ostringstream oss; + oss << einfo.msg << "\n"; + + if (einfo.errPos.has_value() && *einfo.errPos) { + oss << "\n"; + printAtPos(*einfo.errPos, oss); - if (einfo.errPos.has_value() && (*einfo.errPos)) { auto loc = getCodeLines(*einfo.errPos); // lines of code. if (loc.has_value()) { - if (nl) - out << std::endl << prefix; - printCodeLines(out, prefix, *einfo.errPos, *loc); - nl = true; + oss << "\n"; + printCodeLines(oss, "", *einfo.errPos, *loc); + oss << "\n"; } } - // hint - if (einfo.hint.has_value()) { - if (nl) - out << std::endl << prefix; - out << std::endl << prefix << *einfo.hint; - nl = true; - } - // traces - if (showTrace && !einfo.traces.empty()) - { - const string tracetitle(" show-trace "); - - int fill = errwidth - tracetitle.length(); - int lw = 0; - int rw = 0; - const int min_dashes = 3; - if (fill > min_dashes * 2) { - if (fill % 2 != 0) { - lw = fill / 2; - rw = lw + 1; - } - else - { - lw = rw = fill / 2; - } - } - else - lw = rw = min_dashes; - - if (nl) - out << std::endl << prefix; - - out << ANSI_BLUE << std::string(lw, '-') << tracetitle << std::string(rw, '-') << ANSI_NORMAL; - - for (auto iter = einfo.traces.rbegin(); iter != einfo.traces.rend(); ++iter) - { - out << std::endl << prefix; - out << ANSI_BLUE << "trace: " << ANSI_NORMAL << iter->hint.str(); + if (showTrace && !einfo.traces.empty()) { + for (auto iter = einfo.traces.rbegin(); iter != einfo.traces.rend(); ++iter) { + oss << "\n" << "… " << iter->hint.str() << "\n"; if (iter->pos.has_value() && (*iter->pos)) { auto pos = iter->pos.value(); - out << std::endl << prefix; - printAtPos(prefix, pos, out); + oss << "\n"; + printAtPos(pos, oss); auto loc = getCodeLines(pos); - if (loc.has_value()) - { - out << std::endl << prefix; - printCodeLines(out, prefix, pos, *loc); - out << std::endl << prefix; + if (loc.has_value()) { + oss << "\n"; + printCodeLines(oss, "", pos, *loc); + oss << "\n"; } } } } + out << indent(prefix, std::string(filterANSIEscapes(prefix, true).size(), ' '), chomp(oss.str())); + return out; } } |