ledger/format.h
John Wiegley 9a9e06554e Formatting now relies exclusively on value expressions.
What this means is that the utility code, basic math, value expressions,
string formatting and option handling are now entirely decoupled from the rest
of the code.  This decoupling not only greatly simplifies the more basic parts
of Ledger, but makes it much easier to test and verify its completeness.

For example, when the formatting code %X is seen by the format parser, it
turns into a call to the expression function fmt_X, which must be defined when
the format string is first compiled against an object.  If that object is a
transaction, the transaction's scope will be the first to have a chance at
providing a definition.  If an account is being reported, it will.  If neither
does, the next scope in sequence -- soon to be the current report -- will, and
then the session object that "owns" the current Ledger session.

In 2.6, the formatting code new everything about transaction and accounts, and
relied on flags to communicate special details between them.  Now the
transaction will offer the details for its own reporting, while the formatter
worries only about strings and how to output them.
2008-08-02 06:42:36 -04:00

112 lines
2.1 KiB
C++

#ifndef _FORMAT_H
#define _FORMAT_H
#include "journal.h"
#include "expr.h"
#include "walk.h"
namespace ledger {
DECLARE_EXCEPTION(format_error, std::runtime_error);
class format_t : public noncopyable
{
struct element_t : public noncopyable
{
#define ELEMENT_ALIGN_LEFT 0x01
#define ELEMENT_HIGHLIGHT 0x02
enum kind_t {
STRING,
EXPR,
#if 0
DEPTH_SPACER
#endif
};
kind_t type;
unsigned char flags;
unsigned char min_width;
unsigned char max_width;
string chars;
expr_t expr;
scoped_ptr<struct element_t> next;
element_t() throw()
: type(STRING), flags(false), min_width(0), max_width(0) {
TRACE_CTOR(element_t, "");
}
~element_t() throw() {
TRACE_DTOR(element_t);
}
friend inline void mark_red(std::ostream& out, const element_t * elem) {
out.setf(std::ios::left);
out.width(0);
out << "\e[31m";
if (elem->flags & ELEMENT_ALIGN_LEFT)
out << std::left;
else
out << std::right;
if (elem->min_width > 0)
out.width(elem->min_width);
}
void dump(std::ostream& out) const;
};
string format_string;
scoped_ptr<element_t> elements;
enum elision_style_t {
TRUNCATE_TRAILING,
TRUNCATE_MIDDLE,
TRUNCATE_LEADING,
ABBREVIATE
};
static elision_style_t elision_style;
static int abbrev_length;
static bool ansi_codes;
static bool ansi_invert;
public:
format_t() {
TRACE_CTOR(format_t, "");
}
format_t(const string& _format) {
TRACE_CTOR(format_t, "const string&");
parse(_format);
}
~format_t() {
TRACE_DTOR(format_t);
}
void parse(const string& _format) {
elements.reset(parse_elements(_format));
format_string = _format;
}
void format(std::ostream& out, scope_t& scope);
void dump(std::ostream& out) const {
for (const element_t * elem = elements.get();
elem;
elem = elem->next.get())
elem->dump(out);
}
private:
static element_t * parse_elements(const string& fmt);
static string truncate(const string& str, unsigned int width,
const bool is_account = false);
};
} // namespace ledger
#endif // _FORMAT_H