From 5da1e7756d2a4eb04753b8a97bc00063b4d3f687 Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Fri, 18 Jun 2010 02:26:50 -0400 Subject: Added new option --inject=KEY[,KEY...] If you have a typed metadata key which contains an amount, you can use --inject=KEY to inject a posting with that amount wherever a match occurs. There are two main forms of usage: 2010-06-18 Sample ; Key:: $100 Expenses:Food $100.00 Assets:Checking The command would be: ledger reg --inject=Key In the above, transactional form, a posting under the account "Key" will be injected before the first posting reported for this transaction. It's amount will be $100. This only happens once for the whole transaction. It is also possible to associate the key with a posting: 2010-06-18 Sample Expenses:Food $100.00 ; Key:: $100 Assets:Checking Now the injected posting is generated whenever that particular post is reported. --- doc/ledger.1 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'doc') diff --git a/doc/ledger.1 b/doc/ledger.1 index 4e72c792..ba4317f9 100644 --- a/doc/ledger.1 +++ b/doc/ledger.1 @@ -1,4 +1,4 @@ -.Dd June 15, 2010 +.Dd June 18, 2010 .Dt ledger 1 .Sh NAME .Nm ledger @@ -336,6 +336,7 @@ See .It Fl \-help-disp .It Fl \-import Ar STR .It Fl \-init-file Ar FILE +.It Fl \-inject Ar STR .It Fl \-input-date-format Ar DATEFMT .It Fl \-invert .It Fl \-last Ar INT -- cgit v1.2.3 From 6fd512cc117ebb61ced94f2d67f69ae5ed81b60b Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Sat, 19 Jun 2010 13:34:03 -0400 Subject: Added NEWS entries for 2.6.2 and 2.6.3 --- doc/NEWS | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'doc') diff --git a/doc/NEWS b/doc/NEWS index 100e4ea2..1d4826dc 100644 --- a/doc/NEWS +++ b/doc/NEWS @@ -13,6 +13,23 @@ features, please see the manual. To see 2.6 behavior, use "bal -n" in 3.0. The -s option no longer has any effect on balance reports. +* 2.6.3 + +- Minor fixes to allow for compilation with gcc 4.4. + +* 2.6.2 + +- Bug fix: Command-line options, such as -O, now override init-file options + such as -V. + +- Bug fix: "cat data | ledger -f -" now works. + +- Bug fix: --no-cache is now honored. Previously, it was writing out a cache + file named "". + +- Bug fix: Using %.2X in a format string now outputs 2 spaces if the state is + cleared. + * 2.6.1 - Added the concept of "balance setting transactions": -- cgit v1.2.3 From b589829646ececc31adadeb223435ccc2bb716c3 Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Sat, 19 Jun 2010 15:47:32 -0400 Subject: Initial skeleton for the 3.0 manual --- doc/ledger3.texi | 322 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 322 insertions(+) create mode 100644 doc/ledger3.texi (limited to 'doc') diff --git a/doc/ledger3.texi b/doc/ledger3.texi new file mode 100644 index 00000000..3a44803f --- /dev/null +++ b/doc/ledger3.texi @@ -0,0 +1,322 @@ +\input texinfo @c -*-texinfo-*- + +@setfilename ledger.info +@settitle Ledger: Command-Line Accounting + +@dircategory User Applications +@copying +Copyright (c) 2003-2010, John Wiegley. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +- Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +- Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +- Neither the name of New Artisans LLC nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +@end copying + +@documentencoding UTF-8 + +@iftex +@finalout +@end iftex + +@titlepage +@title Ledger: Command-Line Accounting +@author John Wiegley +@end titlepage + +@direntry +* Ledger: (ledger). Command-Line Accounting +@end direntry + +@contents + +@ifnottex +@node Top, , (dir), (dir) +@top Overview + +@insertcopying +@end ifnottex + +@ifnottex +@section Copyright +@insertcopying +@end ifnottex + +@chapter Introduction + +@chapter Principles of accounting + +@chapter Keeping a journal + +@chapter Basic reporting commands + +@chapter Command-line syntax + +@chapter Journal data format + +This chapter offers a complete description of the journal data format, +suitable for implementors in other languages to follow. For users, +the chapter on keeping a journal is less extensive, but more typical +of common usage (@pxref{Keeping a journal}). + +Data is collected in the form of @dfn{transactions} which occur in one +or more @dfn{journal files}. Each transaction, in turn, is made up of +one or more @dfn{postings}, which describe how @dfn{amounts} flow from +one @dfn{account} to another. Here is an example of the simplest of +journal files: + +@example +2010/05/31 Just an example + Expenses:Some:Account $100.00 + Income:Another:Account +@end example + +In this example, there is a transaction date, a payee, or description +of the transaction, and two postings. The postings show movement of +one hundred dollars from an account within the Income hierarchy, to +the specified expense account. The name and meaning of these accounts +in arbitrary, with no preferences implied, although you will find it +useful to follow standard accounting practice (@pxref{Principles of +accounting}}. + +Since an amount is missing from the second posting, it is assumed to +be the inverse of the first. This guarantee the cardinal rule of +double-entry accounting: the sum of every transaction must balance to +zero, or it is in error. Whenever Ledger encounters a @dfn{null +posting} in a transaction, it uses it to balance the remainder. + +It is also typical---though not enforced---to think of the first +posting as the destination, and the final as the source. Thus, the +amount of the first posting is typically positive. Consider: + +@example +2010/05/31 An income transaction + Assets:Checking $1,000.00 + Income:Salary + +2010/05/31 An expense transaction + Expenses:Dining $100.00 + Assets:Checking +@end example + +@section Specifying amounts + +The heart of a journal is the amounts it records, and this fact is +reflected in the diversity of amount expressions allowed. All of them +are covered here, though it must be said that sometimes, there are +multiple ways to achieve a desired result. + +@subsection Integer amounts + +In the simplest form, bare decimal numbers are accepted: + +@example +2010/05/31 An income transaction + Assets:Checking 1000.00 + Income:Salary +@end example + +Such amounts may only use an optional period for a decimal point. +These are referred to as @dfn{integer amounts} or @dfn{uncommoditized +amounts}. In most ways they are similar to @dfn{commoditized +amounts}, but for one signficant difference: They always display in +reports with @dfn{full precision}. More on this in a moment. For +now, a word must be said about how Ledger stores numbers. + +Every number parsed by Ledger is stored internally as an +infinite-precision rational value. Floating-point math is never used, +as it cannot be trusted to maintain precision of values. So, in the +case of @samp{1000.00} above, the internal value is @samp{100000/100}. + +While rational numbers are great at not losing precision, the question +arises: How should they be displayed? A number like @samp{100000/100} +is no problem, since it represents a clean decimal fraction. But what +about when the number @samp{1/1} is divided by three? How should one +print @samp{1/3}, an infinitely repeating decimal? + +Ledger gets around this problem by rendering rationals into decimal at +the last possible moment, and only for display. As such, some +rounding must, at times, occur. If this rounding would affect the +calculation of a running total, special accommodation postings are +generated to make you aware it has happened. In practice, it happens +rarely, but even then it does not reflect adjustment of the +@emph{internal amount}, only the displayed amount. + +What has still not been answered is how Ledger rounds values. Should +@samp{1/3} be printed as @samp{0.33} or @samp{0.33333}? For +commoditized amounts, the number of decimal places is decided by +observing how each commodity is used; but in the case of integer +amounts, an arbitrary factor must be chosen. Initially, this factor +is six. Thus, @samp{1/3} is printed back as @samp{0.333333}. +Further, this rounding factor becomes associated with each particular +value, and is carried through mathematical operations. For example, +if that particular number were multiplied by itself, the decimal +precision of the result would be twelve. Addition and subtraction do +not affect precision. + +Since each integer amount retains its own display precision, this is +called @dfn{full precision}, as opposed to commoditized amounts, which +always look to their commodity to know what precision they should +round to, and so use @dfn{commodity precision}. + +@subsection Commoditized amounts + +A @dfn{commoditized amount} is an integer amount which has an +associated commodity. This commodity can appear before or after the +amount, and may or may not be separated from it by a space. Most +characters are allowed in a commodity name, except for the following: + +@itemize +@item Any kind of whitespace +@item Numerical digits +@item Punctuation: @samp{.,;:?!} +@item Mathematical and logical operators: @samp{-+*/^&|=} +@item Bracketing characters: @samp{<>[](){}} +@item The at symbol: @samp{@} +@end itemize + +And yet, any of these may appear in a commodity name if it is +surrounded by double quotes, for example: + +@example +100 "EUN+133" +@end example + +If a @dfn{quoted commodity} is found, it is displayed in quotes as +well, to avoid any confusion as to which part is the amount, and which +part is the commodity. + +Another feature of commoditized amounts is that they are reported back +in the same form as parsed. If you specify dollar amounts using +@samp{$100}, they will print the same; likewise with @samp{100 $} or +@samp{$100.000}. You may even use decimal commas, such as +@samp{$100,00}, or thousand-marks, as in @samp{$10,000.00}. + +These display characteristics become associated with the commodity, +with the result being that all amounts of the same commodity are +reported consistently. Where this is most noticeable is the +@dfn{display precision}, which is determined by the most precise value +seen for a given commodity. In most cases. + +Ledger makes a distinction by @dfn{observed amounts} and unobserved +amounts. An observed amount is critiqued by Ledger to determine how +amounts using that commodity should be displayed; unobserved amounts +are significant in their value only---no matter how they are +specified, it does not change how other amounts in that commodity will +be displayed. + +An example of this is found in cost expressions, covered next. + +@section Posting costs + +You have seen how to specify either a commoditized or an integer +amount for a posting. But what if the amount you paid for something +was in one commodity, and the amount received was another? There are +two main ways to express this: + +@example +2010/05/31 Farmer's Market + Assets:My Larder 100 apples + Assets:Checking $20.00 +@end example + +In this example, you have paid twenty dollars for one hundred apples. +The cost to you is twenty cents per apple, and Ledger calculates this +implied cost for you. You can also make the cost explicit using a +@dfn{cost amount}: + +@example +2010/05/31 Farmer's Market + Assets:My Larder 100 apples @ $0.200000 + Assets:Checking +@end example + +Here the @dfn{per-unit cost} is given explicitly in the form of a cost +amount; and since cost amount are @emph{unobserved}, the use of six +decimal places has no effect on how dollar amounts are displayed in +the final report. You can also specify the @dfn{total cost}: + +@example +2010/05/31 Farmer's Market + Assets:My Larder 100 apples @@ $20 + Assets:Checking +@end example + +These three forms have identical meaning. In most cases the first is +preferred, but the second two are necessary when more than two +postings are involved: + +@example +2010/05/31 Farmer's Market + Assets:My Larder 100 apples @ $0.200000 + Assets:My Larder 100 pineapples @ $0.33 + Assets:My Larder 100 "crab apples" @ $0.04 + Assets:Checking +@end example + +Here the implied cost is @samp{$57.00}, which is entered into the null +posting automatically so that the transaction balances. + +@subsection Primary commodities + +In every transaction involving more than one commodity, there is +always one which is the @dfn{primary commodity}. This commodity +should be thought of as the exchange commodity, or the commodity used +to buy and sells units of the other commodity. In the fruit examples +above, dollars are the primary commodity. This is decided by Ledger +on the placement of the commodity in the transaction: + +@example +2010/05/31 Sample Transaction + Expenses 100 secondary + Assets 50 primary + +2010/05/31 Sample Transaction + Expenses 100 secondary @ 0.5 primary + Assets + +2010/05/31 Sample Transaction + Expenses 100 secondary @@ 50 primary + Assets +@end example + +The only case where knowledge of primary versus secondary comes into +play is in reports that use the @option{-V} or @option{-B} options. +With these, only primary commodities are shown. + +If a transaction uses only one commodity, this commodity is also +considered a primary. In fact, when Ledger goes about ensures that +all transactions balance to zero, it only ever asks this of primary +commodities. + +@chapter Report queries + +@chapter Value expressions + +@chapter Format strings + +@chapter Extending with Python + +@bye -- cgit v1.2.3 From 81bf38584e43e5fc31e316246f11e210418548a9 Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Tue, 22 Jun 2010 01:16:29 -0400 Subject: Added new --bold-if option --- doc/ledger.1 | 3 +- src/report.cc | 11 ++++++++ src/report.h | 64 +++++++++++++++++++++++++++++++----------- test/baseline/opt-bold-if.test | 0 4 files changed, 61 insertions(+), 17 deletions(-) create mode 100644 test/baseline/opt-bold-if.test (limited to 'doc') diff --git a/doc/ledger.1 b/doc/ledger.1 index ba4317f9..5a3bd6db 100644 --- a/doc/ledger.1 +++ b/doc/ledger.1 @@ -1,4 +1,4 @@ -.Dd June 18, 2010 +.Dd June 22, 2010 .Dt ledger 1 .Sh NAME .Nm ledger @@ -275,6 +275,7 @@ transactions they are contained in. See the manual for more information. .It Fl \-base .It Fl \-basis Pq Fl B .It Fl \-begin Ar DATE Pq Fl b +.It Fl \-bold-if Ar EXPR .It Fl \-budget .It Fl \-budget-format Ar FMT .It Fl \-by-payee Pq Fl P diff --git a/src/report.cc b/src/report.cc index df37f9dc..77cfaffd 100644 --- a/src/report.cc +++ b/src/report.cc @@ -457,6 +457,14 @@ value_t report_t::fn_display_total(call_scope_t& scope) return HANDLER(display_total_).expr.calc(scope); } +value_t report_t::fn_should_bold(call_scope_t& scope) +{ + if (HANDLED(bold_if_)) + return HANDLER(bold_if_).expr.calc(scope); + else + return false; +} + value_t report_t::fn_market(call_scope_t& args) { optional moment = (args.has(1) ? @@ -905,6 +913,7 @@ option_t * report_t::lookup_option(const char * p) else OPT(base); else OPT_ALT(basis, cost); else OPT_(begin_); + else OPT(bold_if_); else OPT(budget); else OPT(by_payee); break; @@ -1226,6 +1235,8 @@ expr_t::ptr_op_t report_t::lookup(const symbol_t::kind_t kind, return MAKE_FUNCTOR(report_t::fn_scrub); else if (is_eq(p, "strip")) return MAKE_FUNCTOR(report_t::fn_strip); + else if (is_eq(p, "should_bold")) + return MAKE_FUNCTOR(report_t::fn_should_bold); break; case 't': diff --git a/src/report.h b/src/report.h index e0073193..fc2fc1a2 100644 --- a/src/report.h +++ b/src/report.h @@ -140,6 +140,7 @@ public: value_t fn_total_expr(call_scope_t& scope); value_t fn_display_amount(call_scope_t& scope); value_t fn_display_total(call_scope_t& scope); + value_t fn_should_bold(call_scope_t& scope); value_t fn_market(call_scope_t& scope); value_t fn_get_at(call_scope_t& scope); value_t fn_is_seq(call_scope_t& scope); @@ -379,9 +380,13 @@ public: OPTION__(report_t, balance_format_, CTOR(report_t, balance_format_) { on(none, - "%(justify(scrub(display_total), 20, 20 + prepend_width, true, color))" + "%(ansify_if(" + " justify(scrub(display_total), 20, 20 + prepend_width, true, color)," + " bold if should_bold))" " %(!options.flat ? depth_spacer : \"\")" - "%-(ansify_if(partial_account(options.flat), blue if color))\n%/" + "%-(ansify_if(" + " ansify_if(partial_account(options.flat), blue if color)," + " bold if should_bold))\n%/" "%$1\n%/" "--------------------\n"); }); @@ -405,6 +410,18 @@ public: parent->HANDLER(limit_).on(string("--begin"), predicate); }); + OPTION__ + (report_t, bold_if_, + expr_t expr; + CTOR(report_t, bold_if_) {} + void set_expr(const optional& whence, const string& str) { + expr = str; + on(whence, str); + } + DO_(args) { + set_expr(args.get(0), args.get(1)); + }); + OPTION_(report_t, budget, DO() { parent->budget_flags |= BUDGET_BUDGETED; }); @@ -808,21 +825,36 @@ public: OPTION__(report_t, register_format_, CTOR(report_t, register_format_) { on(none, - "%(ansify_if(justify(format_date(date), date_width), green " - " if color & date > today))" - " %(ansify_if(justify(truncated(payee, payee_width), payee_width), " - " bold if color & !cleared & actual))" - " %(ansify_if(justify(truncated(display_account, account_width, " - " abbrev_len), account_width), blue if color))" - " %(justify(scrub(display_amount), amount_width, " - " 3 + meta_width + date_width + payee_width + account_width" - " + amount_width + prepend_width, true, color))" - " %(justify(scrub(display_total), total_width, " - " 4 + meta_width + date_width + payee_width + account_width" - " + amount_width + total_width + prepend_width, true, color))\n%/" + "%(ansify_if(" + " ansify_if(justify(format_date(date), date_width)," + " green if color and date > today)," + " bold if should_bold))" + " %(ansify_if(" + " ansify_if(justify(truncated(payee, payee_width), payee_width), " + " bold if color and !cleared and actual)," + " bold if should_bold))" + " %(ansify_if(" + " ansify_if(justify(truncated(display_account, account_width, " + " abbrev_len), account_width)," + " blue if color)," + " bold if should_bold))" + " %(ansify_if(" + " justify(scrub(display_amount), amount_width, " + " 3 + meta_width + date_width + payee_width" + " + account_width + amount_width + prepend_width," + " true, color)," + " bold if should_bold))" + " %(ansify_if(" + " justify(scrub(display_total), total_width, " + " 4 + meta_width + date_width + payee_width" + " + account_width + amount_width + total_width" + " + prepend_width, true, color)," + " bold if should_bold))\n%/" "%(justify(\" \", date_width))" - " %(justify(truncated(has_tag(\"Payee\") ? payee : \" \", " - " payee_width), payee_width))" + " %(ansify_if(" + " justify(truncated(has_tag(\"Payee\") ? payee : \" \", " + " payee_width), payee_width)," + " bold if should_bold))" " %$3 %$4 %$5\n"); }); diff --git a/test/baseline/opt-bold-if.test b/test/baseline/opt-bold-if.test new file mode 100644 index 00000000..e69de29b -- cgit v1.2.3