mu-sexp: add -unix output for json tstamps

The json output (for mu-find etc.) just showed the converted sexp
output, including the clumsy emacs-style tstamps (for changed/date).

Add unix timestamps as well, which are easier to work with outside
emacs.

This handles #2770.
This commit is contained in:
Dirk-Jan C. Binnema
2024-12-07 12:14:55 +02:00
parent 646ad2e840
commit 0e0d4a0cb6

View File

@ -1,5 +1,5 @@
/* /*
** Copyright (C) 2022-2023 Dirk-Jan C. Binnema <djcb@djcbsoftware.nl> ** Copyright (C) 2022-2024 Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
** **
** This program is free software; you can redistribute it and/or modify it ** This program is free software; you can redistribute it and/or modify it
** under the terms of the GNU General Public License as published by the ** under the terms of the GNU General Public License as published by the
@ -60,15 +60,18 @@ parse_list(const std::string& expr, size_t& pos)
Sexp lst{}; Sexp lst{};
++pos; ++pos;
while (expr[pos] != ')' && pos != expr.size()) { while (pos < expr.size() && expr[pos] != ')') {
if (auto&& item = parse(expr, pos); item) if (auto&& item = parse(expr, pos); item)
lst.add(std::move(*item)); lst.add(std::move(*item));
else else
return Err(item.error()); return Err(item.error());
} }
if (expr[pos] != ')') if (pos >= expr.size())
return Err(parsing_error(pos, "expected: ')'"));
else if (expr[pos] != ')')
return Err(parsing_error(pos, "expected: ')' but got '{}'", expr[pos])); return Err(parsing_error(pos, "expected: ')' but got '{}'", expr[pos]));
++pos; ++pos;
return Ok(std::move(lst)); return Ok(std::move(lst));
} }
@ -209,6 +212,17 @@ Sexp::to_string(Format fopts) const
// LCOV_EXCL_START // LCOV_EXCL_START
// convert emacs-timestamp (a list) to a unix-tstamp
static uint64_t
unix_tstamp(const Sexp& emacs_tstamp)
{
if (!emacs_tstamp.listp() || emacs_tstamp.list().size() < 2)
throw std::runtime_error("unexpected type");
const auto& lst{emacs_tstamp.list()};
return (lst.at(0).number() << 16) | lst.at(1).number();
}
std::string std::string
Sexp::to_json_string(Format fopts) const Sexp::to_json_string(Format fopts) const
{ {
@ -222,11 +236,18 @@ Sexp::to_json_string(Format fopts) const
auto it{list().begin()}; auto it{list().begin()};
bool first{true}; bool first{true};
while (it != list().end()) { while (it != list().end()) {
sstrm << (first ? "" : ",") << quote(it->symbol().name) << ":"; const auto key{it->symbol().name};
sstrm << (first ? "" : ",") << quote(key) << ":";
++it; ++it;
sstrm << it->to_json_string(); const auto emacs_tstamp{*it};
sstrm << emacs_tstamp.to_json_string();
++it; ++it;
first = false; first = false;
// special-case: tstamp-fields also get a "unix" value,
// which are easier to work with than the "emacs" timestamps
if (key == ":date" || key == ":changed")
sstrm << "," << quote(key + "-unix") << ":"
<< unix_tstamp(emacs_tstamp);
} }
sstrm << "}"; sstrm << "}";
if (any_of(fopts & Format::SplitList)) if (any_of(fopts & Format::SplitList))