aboutsummaryrefslogtreecommitdiff
path: root/src/libutil/error.cc
diff options
context:
space:
mode:
authorJohn Ericson <John.Ericson@Obsidian.Systems>2021-02-25 20:35:11 +0000
committerJohn Ericson <John.Ericson@Obsidian.Systems>2021-02-25 21:51:05 +0000
commitca0994819d68aee26a2906c37a47ae609ac46c4c (patch)
treec96805c008c22926b1eaadc340a99323d53be532 /src/libutil/error.cc
parent10e81bf871551901ff0383bdede0f79325e93867 (diff)
parentc189031e8be0530d73a817571ad7f81ad5eedce6 (diff)
Merge remote-tracking branch 'upstream/master' into path-info
Diffstat (limited to 'src/libutil/error.cc')
-rw-r--r--src/libutil/error.cc240
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;
}
}