diff options
-rw-r--r-- | Makefile.am | 2 | ||||
-rw-r--r-- | NEWS | 7 | ||||
-rw-r--r-- | amount.cc | 12 | ||||
-rw-r--r-- | amount.h | 56 | ||||
-rw-r--r-- | binary.cc | 14 | ||||
-rw-r--r-- | config.cc | 12 | ||||
-rw-r--r-- | config.h | 2 | ||||
-rw-r--r-- | configure.in | 4 | ||||
-rw-r--r-- | format.cc | 61 | ||||
-rw-r--r-- | format.h | 3 |
10 files changed, 126 insertions, 47 deletions
diff --git a/Makefile.am b/Makefile.am index ba96fd9b..68dd5f48 100644 --- a/Makefile.am +++ b/Makefile.am @@ -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 \ @@ -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: @@ -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(); @@ -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; @@ -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 = @@ -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 }, @@ -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); diff --git a/configure.in b/configure.in index f595d3b7..444ba803 100644 --- a/configure.in +++ b/configure.in @@ -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]) @@ -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; } @@ -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"); } |