mirror of https://github.com/djcb/mu.git
mu: support json output directly
Allow for dumping json directly from the Sexp structures, so we don't need any external libs (i.e. json-glib) anymore.
This commit is contained in:
parent
f2e87ea2d4
commit
d2aa1f91b0
12
configure.ac
12
configure.ac
|
@ -146,14 +146,6 @@ glib_version="$($PKG_CONFIG --modversion glib-2.0)"
|
|||
PKG_CHECK_MODULES(GMIME,gmime-3.0)
|
||||
gmime_version="$($PKG_CONFIG --modversion gmime-3.0)"
|
||||
|
||||
# gmime, version 3.0 or higher
|
||||
PKG_CHECK_MODULES(JSON_GLIB,json-glib-1.0 >= 1.4,[have_json_glib=yes],[have_json_glib=no])
|
||||
AS_IF([test "x$have_json_glib" = "xyes"],[
|
||||
json_glib_version="$($PKG_CONFIG --modversion json-glib-1.0)"
|
||||
AC_DEFINE(HAVE_JSON_GLIB,[1], [Do we support json-glib?])
|
||||
])
|
||||
AM_CONDITIONAL(HAVE_JSON_GLIB,[test "x$have_json_glib" = "xyes"])
|
||||
|
||||
# xapian checking - we need 1.4 at least
|
||||
PKG_CHECK_MODULES(XAPIAN,xapian-core >= 1.4,[
|
||||
have_xapian=yes
|
||||
|
@ -296,10 +288,6 @@ echo "Xapian version : $xapian_version"
|
|||
echo "GLib version : $glib_version"
|
||||
echo "GMime version : $gmime_version"
|
||||
|
||||
AM_COND_IF([HAVE_JSON_GLIB],[
|
||||
echo "Json-Glib version : $json_glib_version"
|
||||
])
|
||||
|
||||
AM_COND_IF([BUILD_GUI],[
|
||||
echo "GTK+ version : $gtk_version"
|
||||
echo "Webkit2/GTK+ version : $webkit_version"
|
||||
|
|
|
@ -20,13 +20,6 @@ include $(top_srcdir)/gtest.mk
|
|||
|
||||
SUBDIRS= utils query index
|
||||
|
||||
if HAVE_JSON_GLIB
|
||||
json_srcs= \
|
||||
mu-msg-json.c \
|
||||
mu-msg-json.h
|
||||
json_flag="-DHAVE_JSON_GLIB"
|
||||
endif
|
||||
|
||||
TESTDEFS= \
|
||||
-DMU_TESTMAILDIR=\"${abs_srcdir}/testdir\" \
|
||||
-DMU_TESTMAILDIR2=\"${abs_srcdir}/testdir2\" \
|
||||
|
|
|
@ -478,5 +478,14 @@ mu_msg_to_sexp (MuMsg *msg, unsigned docid, const MuMsgIterThreadInfo *ti,
|
|||
MuMsgOptions opts)
|
||||
{
|
||||
return g_strdup (Mu::msg_to_sexp (msg, docid, ti, opts)
|
||||
.to_string().c_str());
|
||||
.to_sexp_string().c_str());
|
||||
}
|
||||
|
||||
|
||||
char*
|
||||
mu_msg_to_json (MuMsg *msg, unsigned docid, const MuMsgIterThreadInfo *ti,
|
||||
MuMsgOptions opts)
|
||||
{
|
||||
return g_strdup (Mu::msg_to_sexp (msg, docid, ti, opts)
|
||||
.to_json_string().c_str());
|
||||
}
|
||||
|
|
10
lib/mu-msg.h
10
lib/mu-msg.h
|
@ -595,10 +595,6 @@ char* mu_str_flags (MuFlags flags)
|
|||
|
||||
struct _MuMsgIterThreadInfo;
|
||||
|
||||
#ifdef HAVE_JSON_GLIB
|
||||
|
||||
struct _JsonNode; /* forward declaration */
|
||||
|
||||
/**
|
||||
* convert the msg to json
|
||||
*
|
||||
|
@ -612,13 +608,11 @@ struct _JsonNode; /* forward declaration */
|
|||
* - MU_MSG_OPTION_EXTRACT_IMAGES: extract image attachments as temporary
|
||||
* files and include links to those in the sexp
|
||||
*
|
||||
* @return a string with the sexp (free with g_free) or NULL in case of error
|
||||
* @return a string with the json (free with g_free) or NULL in case of error
|
||||
*/
|
||||
struct _JsonNode* mu_msg_to_json (MuMsg *msg, unsigned docid,
|
||||
char* mu_msg_to_json (MuMsg *msg, unsigned docid,
|
||||
const struct _MuMsgIterThreadInfo *ti,
|
||||
MuMsgOptions ops) G_GNUC_WARN_UNUSED_RESULT;
|
||||
#endif /*HAVE_JSON_GLIB*/
|
||||
|
||||
|
||||
/**
|
||||
* convert the msg to a Lisp symbolic expression (for further processing in
|
||||
|
|
|
@ -33,7 +33,7 @@ Command::invoke(const Command::CommandMap& cmap, const Sexp& call)
|
|||
if (!call.is_call()) {
|
||||
throw Mu::Error{Error::Code::Command,
|
||||
"expected call-sexpr but got %s",
|
||||
call.to_string().c_str()};
|
||||
call.to_sexp_string().c_str()};
|
||||
}
|
||||
|
||||
const auto& params{call.list()};
|
||||
|
@ -41,7 +41,7 @@ Command::invoke(const Command::CommandMap& cmap, const Sexp& call)
|
|||
if (cmd_it == cmap.end())
|
||||
throw Mu::Error{Error::Code::Command,
|
||||
"unknown command in call %s",
|
||||
call.to_string().c_str()};
|
||||
call.to_sexp_string().c_str()};
|
||||
|
||||
const auto& cinfo{cmd_it->second};
|
||||
|
||||
|
@ -67,7 +67,7 @@ Command::invoke(const Command::CommandMap& cmap, const Sexp& call)
|
|||
if (arginfo.required)
|
||||
throw Mu::Error{Error::Code::Command,
|
||||
"missing required parameter %s in call %s",
|
||||
argname.c_str(), call.to_string().c_str()};
|
||||
argname.c_str(), call.to_sexp_string().c_str()};
|
||||
continue; // not required
|
||||
}
|
||||
|
||||
|
@ -78,7 +78,7 @@ Command::invoke(const Command::CommandMap& cmap, const Sexp& call)
|
|||
"parameter %s expects type %s, but got %s in call %s",
|
||||
argname.c_str(), to_string(arginfo.type).c_str(),
|
||||
to_string(param_it->type()).c_str(),
|
||||
call.to_string().c_str()};
|
||||
call.to_sexp_string().c_str()};
|
||||
}
|
||||
|
||||
// all passed parameters must be known
|
||||
|
@ -87,7 +87,7 @@ Command::invoke(const Command::CommandMap& cmap, const Sexp& call)
|
|||
[&](auto&& arg) {return params.at(i).value() == arg.first;}))
|
||||
throw Mu::Error{Error::Code::Command,
|
||||
"unknown parameter %s in call %s",
|
||||
params.at(i).value().c_str(), call.to_string().c_str()};
|
||||
params.at(i).value().c_str(), call.to_sexp_string().c_str()};
|
||||
}
|
||||
|
||||
if (cinfo.handler)
|
||||
|
|
|
@ -179,7 +179,7 @@ Sexp::make_parse (const std::string& expr)
|
|||
|
||||
|
||||
std::string
|
||||
Sexp::to_string () const
|
||||
Sexp::to_sexp_string () const
|
||||
{
|
||||
std::stringstream sstrm;
|
||||
|
||||
|
@ -188,7 +188,7 @@ Sexp::to_string () const
|
|||
sstrm << '(';
|
||||
bool first{true};
|
||||
for (auto&& child : list()) {
|
||||
sstrm << (first ? "" : " ") << child.to_string();
|
||||
sstrm << (first ? "" : " ") << child.to_sexp_string();
|
||||
first = false;
|
||||
}
|
||||
sstrm << ')';
|
||||
|
@ -206,3 +206,55 @@ Sexp::to_string () const
|
|||
|
||||
return sstrm.str();
|
||||
}
|
||||
|
||||
|
||||
std::string
|
||||
Sexp::to_json_string () const
|
||||
{
|
||||
std::stringstream sstrm;
|
||||
|
||||
switch (type()) {
|
||||
case Type::List: {
|
||||
// property-lists become JSON objects
|
||||
if (is_prop_list()) {
|
||||
sstrm << "{";
|
||||
auto it{list().begin()};
|
||||
bool first{true};
|
||||
while (it != list().end()) {
|
||||
sstrm << (first?"":",") << quote(it->value()) << ":";
|
||||
++it;
|
||||
sstrm << it->to_json_string();
|
||||
++it;
|
||||
first = false;
|
||||
}
|
||||
sstrm << "}";
|
||||
} else { // other lists become arrays.
|
||||
sstrm << '[';
|
||||
bool first{true};
|
||||
for (auto&& child : list()) {
|
||||
sstrm << (first ? "" : ", ") << child.to_json_string();
|
||||
first = false;
|
||||
}
|
||||
sstrm << ']';
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Type::String:
|
||||
sstrm << quote(value());
|
||||
break;
|
||||
case Type::Symbol:
|
||||
if (is_nil())
|
||||
sstrm << "false";
|
||||
else if (is_t())
|
||||
sstrm << "true";
|
||||
else
|
||||
sstrm << quote(value());
|
||||
break;
|
||||
case Type::Number:
|
||||
case Type::Empty:
|
||||
default:
|
||||
sstrm << value();
|
||||
}
|
||||
|
||||
return sstrm.str();
|
||||
}
|
||||
|
|
|
@ -104,11 +104,19 @@ struct Sexp {
|
|||
}
|
||||
|
||||
/**
|
||||
* Convert a Sexp::Node to its string representation
|
||||
* Convert a Sexp::Node to its S-expression string representation
|
||||
*
|
||||
* @return the string representation
|
||||
*/
|
||||
std::string to_string() const;
|
||||
std::string to_sexp_string() const;
|
||||
|
||||
|
||||
/**
|
||||
* Convert a Sexp::Node to its JSON string representation
|
||||
*
|
||||
* @return the string representation
|
||||
*/
|
||||
std::string to_json_string() const;
|
||||
|
||||
/**
|
||||
* Return the type of this Node.
|
||||
|
@ -341,7 +349,7 @@ operator<<(std::ostream& os, Sexp::Type id)
|
|||
static inline std::ostream&
|
||||
operator<<(std::ostream& os, const Sexp& sexp)
|
||||
{
|
||||
os << sexp.to_string();
|
||||
os << sexp.to_sexp_string();
|
||||
return os;
|
||||
}
|
||||
|
||||
|
|
|
@ -63,17 +63,17 @@ test_list()
|
|||
const auto nstr{Sexp::make_string("foo")};
|
||||
g_assert_true(nstr.value() == "foo");
|
||||
g_assert_true(nstr.type() == Sexp::Type::String);
|
||||
assert_equal(nstr.to_string(), "\"foo\"");
|
||||
assert_equal(nstr.to_sexp_string(), "\"foo\"");
|
||||
|
||||
const auto nnum{Sexp::make_number(123)};
|
||||
g_assert_true(nnum.value() == "123");
|
||||
g_assert_true(nnum.type() == Sexp::Type::Number);
|
||||
assert_equal(nnum.to_string(), "123");
|
||||
assert_equal(nnum.to_sexp_string(), "123");
|
||||
|
||||
const auto nsym{Sexp::make_symbol("blub")};
|
||||
g_assert_true(nsym.value() == "blub");
|
||||
g_assert_true(nsym.type() == Sexp::Type::Symbol);
|
||||
assert_equal(nsym.to_string(), "blub");
|
||||
assert_equal(nsym.to_sexp_string(), "blub");
|
||||
|
||||
Sexp::List list;
|
||||
list .add(Sexp::make_string("foo"))
|
||||
|
@ -85,7 +85,7 @@ test_list()
|
|||
g_assert_true(nlst.type() == Sexp::Type::List);
|
||||
g_assert_true(nlst.list().at(1).value() == "123");
|
||||
|
||||
assert_equal(nlst.to_string(),"(\"foo\" 123 blub)");
|
||||
assert_equal(nlst.to_sexp_string(),"(\"foo\" 123 blub)");
|
||||
}
|
||||
|
||||
|
||||
|
@ -95,7 +95,7 @@ test_prop_list()
|
|||
Sexp::List l1;
|
||||
l1.add_prop(":foo", Sexp::make_string("bar"));
|
||||
Sexp s2{Sexp::make_list(std::move(l1))};
|
||||
assert_equal(s2.to_string(), "(:foo \"bar\")");
|
||||
assert_equal(s2.to_sexp_string(), "(:foo \"bar\")");
|
||||
|
||||
|
||||
Sexp::List l2;
|
||||
|
@ -105,7 +105,7 @@ test_prop_list()
|
|||
Sexp::List l3;
|
||||
l3.add_prop(":cuux", Sexp::make_list(std::move(l2)));
|
||||
Sexp s3{Sexp::make_list(std::move(l3))};
|
||||
assert_equal(s3.to_string(), "(:cuux (:foo \"bar\" :bar 77))");
|
||||
assert_equal(s3.to_sexp_string(), "(:cuux (:foo \"bar\" :bar 77))");
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -122,7 +122,7 @@ test_props()
|
|||
":flub", Sexp::make_symbol("fnord"),
|
||||
":boo", std::move(sexp2));
|
||||
|
||||
assert_equal(sexp.to_string(),
|
||||
assert_equal(sexp.to_sexp_string(),
|
||||
"(:foo \"b\303\244r\" :cuux 123 :flub fnord :boo (\"foo\" 123 blub))");
|
||||
}
|
||||
|
||||
|
|
|
@ -42,10 +42,6 @@
|
|||
#include "mu-cmd.hh"
|
||||
#include "mu-threader.h"
|
||||
|
||||
#ifdef HAVE_JSON_GLIB
|
||||
#include <json-glib/json-glib.h>
|
||||
#endif /*HAVE_JSON_GLIB*/
|
||||
|
||||
using namespace Mu;
|
||||
|
||||
typedef gboolean (OutputFunc) (MuMsg *msg, MuMsgIter *iter,
|
||||
|
@ -539,7 +535,6 @@ to_string (const Mu::Sexp& sexp, bool color, size_t level = 0)
|
|||
}
|
||||
|
||||
|
||||
|
||||
static gboolean
|
||||
output_sexp (MuMsg *msg, MuMsgIter *iter, const MuConfig *opts, GError **err)
|
||||
{
|
||||
|
@ -555,21 +550,15 @@ output_sexp (MuMsg *msg, MuMsgIter *iter, const MuConfig *opts, GError **err)
|
|||
static gboolean
|
||||
output_json (MuMsg *msg, MuMsgIter *iter, const MuConfig *opts, GError **err)
|
||||
{
|
||||
#ifdef HAVE_JSON_GLIB
|
||||
JsonNode *node;
|
||||
const MuMsgIterThreadInfo *ti;
|
||||
char *s;
|
||||
|
||||
if (mu_msg_iter_is_first(iter))
|
||||
g_print ("[\n");
|
||||
|
||||
ti = opts->threads ? mu_msg_iter_get_thread_info (iter) : NULL;
|
||||
node = mu_msg_to_json (msg, mu_msg_iter_get_docid (iter),
|
||||
ti, MU_MSG_OPTION_HEADERS_ONLY);
|
||||
|
||||
s = json_to_string (node, TRUE);
|
||||
json_node_free (node);
|
||||
|
||||
ti = opts->threads ? mu_msg_iter_get_thread_info (iter) : NULL;
|
||||
s = mu_msg_to_json (msg, mu_msg_iter_get_docid (iter),
|
||||
ti, MU_MSG_OPTION_HEADERS_ONLY);
|
||||
fputs (s, stdout);
|
||||
g_free (s);
|
||||
|
||||
|
@ -579,12 +568,6 @@ output_json (MuMsg *msg, MuMsgIter *iter, const MuConfig *opts, GError **err)
|
|||
fputs (",\n", stdout);
|
||||
|
||||
return TRUE;
|
||||
#else
|
||||
g_set_error (err, MU_ERROR_DOMAIN, MU_ERROR_IN_PARAMETERS,
|
||||
"this mu was built without json support");
|
||||
return FALSE;
|
||||
#endif /*HAVE_JSON_GLIB*/
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
|
@ -147,7 +147,7 @@ print_expr (const char* frm, ...)
|
|||
static void
|
||||
print_expr (const Sexp& sexp)
|
||||
{
|
||||
print_expr ("%s", sexp.to_string().c_str());
|
||||
print_expr ("%s", sexp.to_sexp_string().c_str());
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
Loading…
Reference in New Issue