Added --ansi and --ansi-invert options.

This commit is contained in:
John Wiegley 2006-03-13 08:39:12 +00:00
parent fd525ec382
commit 82d0ee869b
10 changed files with 126 additions and 47 deletions

View file

@ -47,7 +47,7 @@ endif
if DEBUG
libledger_la_CXXFLAGS += -DDEBUG_LEVEL=4
endif
libledger_la_LDFLAGS = -release 2.6
libledger_la_LDFLAGS = -release 3.0
pkginclude_HEADERS = \
acconf.h \

7
NEWS
View file

@ -1,11 +1,16 @@
Ledger NEWS
* 2.6
* 3.0
- Error reporting has been greatly improving, now showing full
contextual information for most error messages.
- Added new --ansi reporting option, which shows negative values as
red using ANSI terminal codes; --ansi-invert makes non-negative
values red (which makes more sense for income and budget reports,
for example).
- Added a new --only predicate, which occurs during transaction
processing between --limit and --display. Here is a summary of how
the three supported predicates are used:

View file

@ -1344,7 +1344,7 @@ void amount_t::annotate_commodity(const amount_t& price,
if (commodity().annotated) {
this_ann = &static_cast<annotated_commodity_t&>(commodity());
this_base = this_ann->base;
this_base = this_ann->ptr;
} else {
this_base = &commodity();
}
@ -1392,7 +1392,7 @@ amount_t amount_t::strip_annotations(const bool _keep_price,
(_keep_tag && ! ann_comm.tag.empty()))
{
new_comm = annotated_commodity_t::find_or_create
(*ann_comm.base, _keep_price ? ann_comm.price : amount_t(),
(*ann_comm.ptr, _keep_price ? ann_comm.price : amount_t(),
_keep_date ? ann_comm.date : 0, _keep_tag ? ann_comm.tag : "");
} else {
new_comm = commodity_t::find_or_create(ann_comm.base_symbol());
@ -1465,7 +1465,7 @@ commodity_t * commodity_t::create(const std::string& symbol)
{
std::auto_ptr<commodity_t> commodity(new commodity_t);
commodity->ptr = commodity_base_t::create(symbol);
commodity->base = commodity_base_t::create(symbol);
if (needs_quotes(symbol)) {
commodity->qualified_symbol = "\"";
@ -1607,10 +1607,10 @@ annotated_commodity_t::create(const commodity_t& comm,
commodity->date = date;
commodity->tag = tag;
commodity->base = &comm;
assert(commodity->base);
commodity->ptr = comm.ptr;
commodity->ptr = &comm;
assert(commodity->ptr);
commodity->base = comm.base;
assert(commodity->base);
commodity->qualified_symbol = comm.symbol();

View file

@ -444,25 +444,25 @@ class commodity_t
typedef unsigned long ident_t;
ident_t ident;
commodity_base_t * ptr;
commodity_base_t * base;
std::string qualified_symbol;
bool annotated;
public:
explicit commodity_t() : ptr(NULL), annotated(false) {}
explicit commodity_t() : base(NULL), annotated(false) {}
operator bool() const {
return this != null_commodity;
}
bool operator==(const commodity_t& comm) const {
return ptr == comm.ptr;
return base == comm.base;
}
bool operator!=(const commodity_t& comm) const {
return ptr != comm.ptr;
return base != comm.base;
}
std::string base_symbol() const {
return ptr->symbol;
return base->symbol;
}
std::string symbol() const {
return qualified_symbol;
@ -473,69 +473,69 @@ class commodity_t
}
std::string name() const {
return ptr->name;
return base->name;
}
void set_name(const std::string& arg) {
ptr->name = arg;
base->name = arg;
}
std::string note() const {
return ptr->note;
return base->note;
}
void set_note(const std::string& arg) {
ptr->note = arg;
base->note = arg;
}
unsigned char precision() const {
return ptr->precision;
return base->precision;
}
void set_precision(unsigned char arg) {
ptr->precision = arg;
base->precision = arg;
}
unsigned char flags() const {
return ptr->flags;
return base->flags;
}
void set_flags(unsigned char arg) {
ptr->flags = arg;
base->flags = arg;
}
void add_flags(unsigned char arg) {
ptr->flags |= arg;
base->flags |= arg;
}
void drop_flags(unsigned char arg) {
ptr->flags &= ~arg;
base->flags &= ~arg;
}
amount_t * smaller() const {
return ptr->smaller;
return base->smaller;
}
void set_smaller(const amount_t& arg) {
if (ptr->smaller)
delete ptr->smaller;
ptr->smaller = new amount_t(arg);
if (base->smaller)
delete base->smaller;
base->smaller = new amount_t(arg);
}
amount_t * larger() const {
return ptr->larger;
return base->larger;
}
void set_larger(const amount_t& arg) {
if (ptr->larger)
delete ptr->larger;
ptr->larger = new amount_t(arg);
if (base->larger)
delete base->larger;
base->larger = new amount_t(arg);
}
commodity_base_t::history_t * history() const {
return ptr->history;
return base->history;
}
void add_price(const std::time_t date, const amount_t& price) {
return ptr->add_price(date, price);
return base->add_price(date, price);
}
bool remove_price(const std::time_t date) {
return ptr->remove_price(date);
return base->remove_price(date);
}
amount_t value(const std::time_t moment = std::time(NULL)) const {
return ptr->value(moment);
return base->value(moment);
}
bool valid() const;
@ -544,7 +544,7 @@ class commodity_t
class annotated_commodity_t : public commodity_t
{
public:
const commodity_t * base;
const commodity_t * ptr;
amount_t price;
std::time_t date;

View file

@ -455,7 +455,7 @@ inline commodity_t * read_binary_commodity(char *& data)
commodity_t * commodity = new commodity_t;
*commodities_next++ = commodity;
commodity->ptr =
commodity->base =
base_commodities[read_binary_long<commodity_base_t::ident_t>(data) - 1];
read_binary_string(data, commodity->qualified_symbol);
@ -469,13 +469,13 @@ inline commodity_t * read_binary_commodity_annotated(char *& data)
annotated_commodity_t * commodity = new annotated_commodity_t;
*commodities_next++ = commodity;
commodity->ptr =
commodity->base =
base_commodities[read_binary_long<commodity_base_t::ident_t>(data) - 1];
read_binary_string(data, commodity->qualified_symbol);
commodity->annotated = true;
commodity->base =
commodity->ptr =
commodities[read_binary_long<commodity_t::ident_t>(data) - 1];
read_binary_amount(data, commodity->price);
read_binary_long(data, commodity->date);
@ -658,7 +658,7 @@ unsigned int read_binary_journal(std::istream& in,
if (read_binary_number<char>(data) == 0) {
commodity = read_binary_commodity(data);
mapping_key = commodity->ptr->symbol;
mapping_key = commodity->base->symbol;
} else {
read_binary_string(data, mapping_key);
commodity = read_binary_commodity_annotated(data);
@ -677,7 +677,7 @@ unsigned int read_binary_journal(std::istream& in,
commodity));
if (! result.second && commodity->annotated)
throw new error(std::string("Failed to read commodity from cache: ") +
commodity->ptr->symbol);
commodity->base->symbol);
}
commodity_t::ident_t ident;
@ -1005,7 +1005,7 @@ void write_binary_commodity(std::ostream& out, commodity_t * commodity)
{
commodity->ident = ++commodity_index;
write_binary_long(out, commodity->ptr->ident);
write_binary_long(out, commodity->base->ident);
write_binary_string(out, commodity->qualified_symbol);
}
@ -1014,7 +1014,7 @@ void write_binary_commodity_annotated(std::ostream& out,
{
commodity->ident = ++commodity_index;
write_binary_long(out, commodity->ptr->ident);
write_binary_long(out, commodity->base->ident);
write_binary_string(out, commodity->qualified_symbol);
annotated_commodity_t * ann_comm =

View file

@ -1115,6 +1115,16 @@ OPT_BEGIN(total_data, "J") {
config->format_string = config->plot_total_format;
} OPT_END(total_data);
OPT_BEGIN(ansi, "") {
format_t::ansi_codes = true;
format_t::ansi_invert = false;
} OPT_END(ansi);
OPT_BEGIN(ansi_invert, "") {
format_t::ansi_codes =
format_t::ansi_invert = true;
} OPT_END(ansi);
//////////////////////////////////////////////////////////////////////
//
// Commodity reporting
@ -1192,6 +1202,8 @@ option_t config_options[CONFIG_OPTIONS_SIZE] = {
{ "add-budget", '\0', false, opt_add_budget, false },
{ "amount", 't', true, opt_amount, false },
{ "amount-data", 'j', false, opt_amount_data, false },
{ "ansi", '\0', false, opt_ansi, false },
{ "ansi-invert", '\0', false, opt_ansi_invert, false },
{ "average", 'A', false, opt_average, false },
{ "balance-format", '\0', true, opt_balance_format, false },
{ "basis", 'B', false, opt_basis, false },

View file

@ -107,7 +107,7 @@ class config_t
std::list<item_handler<transaction_t> *>& ptrs);
};
#define CONFIG_OPTIONS_SIZE 86
#define CONFIG_OPTIONS_SIZE 88
extern option_t config_options[CONFIG_OPTIONS_SIZE];
void option_help(std::ostream& out);

View file

@ -2,8 +2,8 @@
# Process this file with autoconf to produce a configure script.
AC_PREREQ(2.59)
AC_INIT(ledger, 2.6, johnw@newartisans.com)
AM_INIT_AUTOMAKE(ledger, 2.6)
AC_INIT(ledger, 3.0, johnw@newartisans.com)
AM_INIT_AUTOMAKE(ledger, 3.0)
AC_CONFIG_SRCDIR([main.cc])
AC_CONFIG_HEADER([acconf.h])

View file

@ -7,6 +7,9 @@
namespace ledger {
bool format_t::ansi_codes = false;
bool format_t::ansi_invert = false;
std::string truncated(const std::string& str, unsigned int width,
const int style)
{
@ -264,6 +267,26 @@ static bool entry_state(const entry_t * entry, transaction_t::state_t * state)
return ! hetero;
}
namespace {
void mark_red(std::ostream& out, const element_t * elem) {
out.setf(std::ios::left);
out.width(0);
out << "\e[31m";
if (elem->align_left)
out << std::left;
else
out << std::right;
if (elem->min_width > 0)
out.width(elem->min_width);
}
void mark_plain(std::ostream& out) {
out << "\e[0m";
}
}
void format_t::format(std::ostream& out_str, const details_t& details) const
{
for (const element_t * elem = elements; elem; elem = elem->next) {
@ -322,15 +345,37 @@ void format_t::format(std::ostream& out_str, const details_t& details) const
case value_t::BOOLEAN:
out << (*((bool *) value.data) ? "true" : "false");
break;
case value_t::INTEGER:
if (ansi_codes) {
if (ansi_invert) {
if (*((long *) value.data) > 0)
mark_red(out, elem);
} else {
if (*((long *) value.data) < 0)
mark_red(out, elem);
}
}
out << *((long *) value.data);
break;
case value_t::DATETIME:
out << *((datetime_t *) value.data);
break;
case value_t::AMOUNT:
if (ansi_codes) {
if (ansi_invert) {
if (*((amount_t *) value.data) > 0)
mark_red(out, elem);
} else {
if (*((amount_t *) value.data) < 0)
mark_red(out, elem);
}
}
out << *((amount_t *) value.data);
break;
case value_t::BALANCE:
bal = (balance_t *) value.data;
// fall through...
@ -339,14 +384,28 @@ void format_t::format(std::ostream& out_str, const details_t& details) const
if (! bal)
bal = &((balance_pair_t *) value.data)->quantity;
if (ansi_codes) {
if (ansi_invert) {
if (*bal > 0)
mark_red(out, elem);
} else {
if (*bal < 0)
mark_red(out, elem);
}
}
bal->write(out, elem->min_width,
(elem->max_width > 0 ? elem->max_width : elem->min_width));
(elem->max_width > 0 ?
elem->max_width : elem->min_width));
ignore_max_width = true;
break;
default:
assert(0);
break;
}
if (ansi_codes)
mark_plain(out);
break;
}

View file

@ -72,6 +72,9 @@ struct format_t
std::string format_string;
element_t * elements;
static bool ansi_codes;
static bool ansi_invert;
format_t() : elements(NULL) {
DEBUG_PRINT("ledger.memory.ctors", "ctor format_t");
}